ADO.NETEntity-FrameworkObjectContextを使用してデータストアにアクセスしています。
値が空の文字列で設定されている場合、それらは自動的にnullになるはずです。
ADO.NETEntity-FrameworkObjectContextを使用してデータストアにアクセスしています。
値が空の文字列で設定されている場合、それらは自動的にnullになるはずです。
Entity Framework 4を使用している場合は、T4テンプレートを使用してこれを実現できます。これを.ttテンプレートファイルの各文字列プロパティのゲッターに配置するだけで、空の文字列がnullに置き換えられ、文字列が自動的にトリミングされます。リフレクションを使用する必要はありません。
<#+ if (primitiveProperty.TypeUsage.ToString().Split('.').Last() == "String") { #>
if (value == "") value = null;
else value = value.Trim();
<#+ } #>
私は実際にこれに対するより良い方法を見つけました、それは実際にシステムに組み込まれています、そしてそれはとにかくロードされるエンティティの内部序数メタデータを使用します(私はパフォーマンスの違いをテストしていませんが、これははるかに速いはずです反射):
private const string StringType = "String";
private const EntityState SavingState = EntityState.Added | EntityState.Modified;
public override int SaveChanges()
{
//when using on ObjectContext replace 'objectContext' with 'this',
//and override SaveChanges(SaveOptions options) instead:
var objectContext = ((IObjectContextAdapter)this).ObjectContext;
var savingEntries = objectContext.ObjectStateManager
.GetObjectStateEntries(SavingState);
foreach (var entry in savingEntries)
{
var curValues = entry.CurrentValues;
var fieldMetadata = curValues.DataRecordInfo.FieldMetadata;
var stringFields = fieldMetadata
.Where(f => f.FieldType.TypeUsage.EdmType.Name == StringType);
foreach (var stringField in stringFields)
{
var ordinal = stringField.Ordinal;
var curValue = curValues[ordinal] as string;
if (curValue != null && curValue.All(char.IsWhiteSpace))
curValues.SetValue(ordinal, null);
}
}
return base.SaveChanges(); //SaveChanges(options) on ObjectContext
}
上記のコードをEntityFramework4.1(DbContext)の新しいリリースに適合させました。
public override int SaveChanges()
{
var objContext = ((IObjectContextAdapter)this).ObjectContext;
var entries = objContext.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Modified).Select(
entry => entry.Entity);
foreach (var entity in entries)
{
string str = typeof(string).Name;
var properties = from p in entity.GetType().GetProperties()
where p.PropertyType.Name == str
select p;
foreach (var item in properties)
{
string value = (string)item.GetValue(entity, null);
if (value != null && value.Trim().Length == 0)
{
item.SetValue(entity, null, null);
}
}
}
return base.SaveChanges();
私が知っていることではありません。
x.objectlayer.cs / x.designer.csの代わりに、それを継承しObjectContext
てオーバーライドするクラスを作成し、それを使用することもできます。SaveChanges()
ObjectContext
ObjectContextをオーバーライドして複雑にするのではなく、文字列拡張メソッドを使用してデータベースストレージの値を変換します
public static class StringExtensions
{
public static string EmptyStringToNull(this string s)
{
return string.IsNullOrWhiteSpace(s) ? null : s;
}
public static object EmptyStringToDBNull(this string s)
{
if (string.IsNullOrWhiteSpace(s))
return DBNull.Value;
else
return s;
}
}
これがEntityFrameworkCoreのソリューションです(V2でテスト済み)。ドキュメントが限られているため、APIを介して自分の道を切り開く必要があったので、同じことを達成する他の方法があるかもしれません。元のオブジェクトはこのメソッドを使用して変更されることに注意してください。
public override int SaveChanges()
{
ConvertWhitespaceToNulls();
return base.SaveChanges();
}
private void ConvertWhitespaceToNulls()
{
var entityEntries = this.ChangeTracker
.Entries()
.Where(x => x.State == EntityState.Modified || x.State == EntityState.Added && x.Entity != null);
foreach (var e in entityEntries)
foreach (var currentValue in e.CurrentValues.Properties.Where(p => p.ClrType == typeof(string) && p.IsNullable))
if (string.IsNullOrWhiteSpace((string) currentValue.FieldInfo.GetValue(e.Entity)))
currentValue.FieldInfo.SetValue(e.Entity, null);
}
完全を期すために、継承ではなく部分的なクラスとして記述された、受け入れられた回答を次に示します。このバージョンでは文字列もトリミングされることに注意してください。
using System.Data;
using System.Data.Objects;
using System.Linq;
public partial class MyObjectContext {
private const string StringType = "String";
private const EntityState SavingState = EntityState.Added | EntityState.Modified;
public override int SaveChanges(SaveOptions options) {
var savingEntries = this.ObjectStateManager.GetObjectStateEntries(SavingState);
foreach (var entry in savingEntries) {
var curValues = entry.CurrentValues;
var fieldMetadata = curValues.DataRecordInfo.FieldMetadata;
var stringFields = fieldMetadata.Where(f => f.FieldType.TypeUsage
.EdmType.Name == StringType);
foreach (var stringField in stringFields) {
var ordinal = stringField.Ordinal;
var curValue = curValues[ordinal] as string;
if (curValue != null && curValue.All(char.IsWhiteSpace)) {
curValues.SetValue(ordinal, null);
}
else if (curValue != null && curValue != curValue.Trim()) {
curValues.SetValue(ordinal, curValue.Trim());
}
}
}
return base.SaveChanges(options);
}
}
usings
また、'n'pasteコードをコピーするとイライラし、IDEがタイプまたは名前空間が見つからないというエラーをスローするため、必要なものを示しました。
私はShimmyのソリューションを使用し、複雑なタイプの文字列が欠落していることに気付くまで満足していました。言い換えると、コアオブジェクト/レコードだけでなく、その非プリミティブオブジェクトプロパティ、およびそれらのプロパティ、およびそれらのプロパティのnull許容空白のみの文字列をnullにする方法が必要でした...
以下は私の再帰的な適応です。あまり長く生きていないので、その優雅さや制作の質について話すことはできませんが、これまでのところ私にとってはうまくいっているようで、少なくとも他の誰かの出発点として役立つかもしれません。
using System.Data.Entity;
using System.Data.Entity.Core.Metadata.Edm;
using System.Data.Entity.Core.Objects;
using System.Data.Entity.Infrastructure;
using System.Linq;
public class MyDataContext : DbContext
{
public override int SaveChanges()
{
ObjectStateEntry[] savingObjectStateEntries = ((IObjectContextAdapter)this)
.ObjectContext.ObjectStateManager
.GetObjectStateEntries(EntityState.Added | EntityState.Modified).ToArray();
foreach (ObjectStateEntry savingObjectStateEntry in savingObjectStateEntries)
SetEmptyStringsToNull(savingObjectStateEntry.CurrentValues);
return base.SaveChanges();
}
private static void SetEmptyStringsToNull(CurrentValueRecord currentValueRecord)
{
if (currentValueRecord != null)
for (int i = 0; i < currentValueRecord.FieldCount; i++)
if (currentValueRecord[i] is CurrentValueRecord)
SetEmptyStringsToNull(currentValueRecord[i] as CurrentValueRecord);
else if ((currentValueRecord[i] is string)
&& (currentValueRecord.DataRecordInfo.FieldMetadata[i].FieldType as EdmProperty).Nullable
&& string.IsNullOrWhiteSpace(currentValueRecord[i] as string))
currentValueRecord.SetValue(i, null);
}
}