Question

Copying data for file attachments results in zero byte file

I have some code that copies some file attachments from one entity to another. The code simply opens an EntitySchemaQuery to read the files, then creates the file records on the other entity. To copy the file data, I am doing: 

newFile.SetBytesValue("Data", origFile.GetBytesValue("Data"));

However, the new file attachment record always only have a zero bytes file (no data is actually copied). 

Does anyone know why this is the case? My assumption is that by reading the file record, the binary Data column isn't actually loaded in the entity. Do I need to do something extra to get the Data column contents?

Like 0

Like

12 comments

I faced a similar issue, but copying the file size to the destination attachment solved the error for me. 

Shivani Lakshman,

The code copying the files does set the Size. Still, the new files end up invalid as zero byte files. 

Ryan

Shivani Lakshman,

For me, I am reading the files via ESQ (and I also tried a Select that I execute as a reader). I create new file Entity and set all fields, setting the Data column as SetColumnBytes. Does this sound similar to how you're doing it (and it works for you?)

Ryan

Ryan Farley,



My use case is to copy the attachments from Orders detail and add it to ActivityFile so that the file can be sent as an email. I guess the case is similar

 

I have the following code to do that



 

private void GetFileFromDB(FileContentInfo f, string schemaName, Guid ActivityId)
        {
            try
            {
                var getFile = new EntitySchemaQuery(UserConnection.EntitySchemaManager, schemaName);
                var dataCol = getFile.AddColumn("Data").Name;
                var sizeCol = getFile.AddColumn("Size").Name;
                var recordFilter = getFile.CreateFilterWithParameters(FilterComparisonType.Equal,
                       "Id", f.FileId);
                getFile.Filters.Add(recordFilter);
 
                var esqResult = getFile.GetEntityCollection(UserConnection);
                foreach (var rec in esqResult)
                {
                    int size = rec.GetTypedColumnValue<int>(sizeCol);
                    byte[] content = new byte[size];
                    f.Size = size;
                    content = rec.GetBytesValue(dataCol);
                    f.FileContent = new MemoryStream(content);
                    f.StatusCode = 200;
                    f.Type = Guid.Parse("529BC2F8-0EE0-DF11-971B-001D60E938C6"); // File type 
                }
            }
            catch (Exception e)
            {
               // logger.Error("Exception in GetFileFromDB" + e.ToString());
                f.FileContent = null;
                f.StatusCode = 500;
                f.ErrorMessage = e.Message;
            }
            finally
            {
                AddToFileHolder(f, ActivityId);
            }
        }
 
private void AddToFileHolder(FileContentInfo fci, Guid ActivityId)
        {
            try
            {
                var entity = UserConnection.EntitySchemaManager.GetInstanceByName("ActivityFile");
                var fileIns = entity.CreateEntity(UserConnection);
                fileIns.SetDefColumnValues();
                Guid fileId = Guid.NewGuid();
                fileIns.SetColumnValue("Id", fileId);
                fileIns.SetColumnValue("Name", fci.FileName);
                fileIns.SetColumnValue("Data", fci.FileContent);
                fileIns.SetColumnValue("ActivityId", ActivityId);
                fileIns.SetColumnValue("Size", fci.Size);
                fileIns.SetColumnValue("TypeId", fci.Type);
                fileIns.SetColumnValue("ErrorOnUpload", fci.ErrorMessage);
                fileIns.Save();
 
            }
            catch (Exception e)
            {
               // logger.Error("AddToFileHolder Exception:" + e.ToString());
            }
 
        }
 

 

Shivani Lakshman,

Thanks for that, this is a big help. For the FileContentInfo object passed into GetFileFromDB, what is that set to in order to call the function? Also, I'm not seeing a FileContentInfo class, is that a class you've defined (I do see a FileUploadInfo)?

Ryan

Ryan Farley,

 

I am passing the necessary values to set in file table as an object. You can perhaps combine the 2 methods into one.

Hello,

any news on this?

 

I have the same problem. Also tried it with a business process and in the trace, it shows that the Data field is null.

 

Thanks,

Robert

Robert Pordes,

I ended up reading the data column for the attachment using the FileRepository class. It looks like this: 

// fileEntityName = an entity such as "AccountFile"
// FileId = the Id of the AccountFile
// also: using Terrasoft.Core.Factories & System.IO
 
var fileRepository = ClassFactory.Get<FileRepository>(new ConstructorArgument("userConnection", UserConnection));
var schema = UserConnection.EntitySchemaManager.GetInstanceByName(fileEntityName);
 
using (var memoryStream = new MemoryStream()) 
{ 
	var bwriter = new BinaryWriter(memoryStream);
	var fileInfo = fileRepository.LoadFile(schema.UId, FileId, bwriter);
	var data = memoryStream.ToArray();
	// data is a byte array and now contains the bytes for the attached file
}

This worked for me.

Ryan

Ryan Farley,

Hi Ryan,

What namespace should I include to use FileRepository? 

 

Thanks,

Rommel

Rommel A Bocker B,

FileRepository is implemented as a source code schema in the configuration, it is a part of Terrasoft.Configuration.

BTW, as a side note, it also reveals why it wasn't working for me in the first place but it was in my dev env. There's a feature called "UseFileCache" which determines whether a file's content can be read as bytes or streamed (guessing based on variable names). It then uses either a FileLoader class or FileCachedLoader class based on that.

Ryan

Ryan Farley,

I found out that using files in a business process should not be done with the normal CRUD tasks. There is a special user task called "Process file".

The user task is implemented in ObjectFileProcessingUserTask.cs

 

So if you want to stick to out-of-the-box file handling, there are examples for reading and copying files.

 

BR,

Robert

Robert Pordes,

I do use the process file task in processes often, the only problem is that the UI for the element only allows you to select file objects for objects that exist as sections (I have many file objects that aren't for sections and you're unable to select them using the process file task). 

Interestingly, the user task uses a FileProcessing class, which uses a FileCopier class that has a Copy method. Ultimately, it gets the file data using: 

var data = sourceEntity.FindEntityColumnValue("Data").StreamBytes;

I wasn't aware of the StreamBytes, I'll have to give that a try since it would be simpler.

Ryan

Show all comments