I have a legacy database that stores user comments (and quite a few other text fields) as blob
datatype, which I cannot change.
I am writing a data access layer that will need to always convert the data to a string
when it is retrieved from the database, and convert it back to blob
when saving.
The EF scaffolding tool generated properties as byte[]
datatype for these entities.
public byte[] Comment { get; set; }
I noticed that if I simply change the entity property type to string
it actually does save the data correctly, but loading the data results in a casting error:
Unable to cast object of type 'System.Byte[]' to type 'System.String'.
(Interestingly, version 1.0.0 did not throw this error, loading and saving worked ok.)
My question is... Is there a way of configuring EF core to automatically convert this data to string when I retrieve it from the database and back to blob
when it gets saved back? Or will I need to write a whole bunch of private getters and setters to do this manipulation?
In addition for my comment on your answere, if you don't want to add getters and setters and want to have clean code, you could also work with extension-methods:
public static class Extensions
{
public static byte[] GetBytes(this string @this, System.Text.Encoding encoding = null)
{
return (encoding??Encoding.UTF8).GetBytes(@this);
}
public static string GetString(this byte[] @this, System.Text.Encoding encoding = null)
{
return (encoding??Encoding.UTF8).GetString(@this);
}
}
you can work with them both this way:
myentity.Comment = "my comment".GetBytes();
string comment = myentity.Comment.GetString();
take care of the default-value in the code, that is UTF8, you can change it to the encoding you want to use, or enter another encoding like
byte[] myBytes = "my comment".GetBytes(Encoding.ASCII);
your win: you don't have to specify a getter/setter to each property using byte[]
Converting the byte[]
into a string
always requires an Encoding
. Since EF does not know which encoding to use, such an automatic conversion is not possible.
What you can do though is to mark your Comment property as private and to create a wrapper property that converts the value to a string with an Encoding
of your choice:
partial class MyEntity
{
private string m_commentText = null;
public string CommentText
{
get {
if ((m_commentText == null) && (Comment != null)) {
m_commentText = Encoding.UTF8.GetString(Comment);
}
return m_commentText;
}
set {
m_commentText = value;
if (value != null) {
Comment = Encoding.UTF8.GetBytes(value);
}
else {
Comment = null;
}
}
}
}
This solution stores the text in a backer field to avoid multiple conversions from byte[]
to string
. If you need the Comment
property to stay public, you need to remove the backer field to avoid data inconsistency:
partial class MyEntity
{
public string CommentText
{
get {
if (Comment != null) {
return Encoding.UTF8.GetString(Comment);
}
else {
return null;
}
}
set {
if (value != null) {
Comment = Encoding.UTF8.GetBytes(value);
}
else {
Comment = null;
}
}
}
}