我正在尝试使用EF6更新记录。首先找到记录,如果它存在,则更新。
这是我的代码:
var book = new Model.Book
{
BookNumber = _book.BookNumber,
BookName = _book.BookName,
BookTitle = _book.BookTitle,
};
using (var db = new MyContextDB())
{
var result = db.Books.SingleOrDefault(b => b.BookNumber == bookNumber);
if (result != null)
{
try
{
db.Books.Attach(book);
db.Entry(book).State = EntityState.Modified;
db.SaveChanges();
}
catch (Exception ex)
{
throw;
}
}
}
每次我尝试使用上面的代码更新记录时,我都会得到这个错误:
{System.Data.Entity.Infrastructure。DbUpdateConcurrencyException:存储
更新、插入或删除语句受影响的数量超出预期
自实体以来,实体可能已被修改或删除
被加载。刷新ObjectStateManager条目
当尝试使用Attach()和SaveChanges()组合更新记录时,我也有同样的问题,但我使用的是SQLite DB及其EF提供者(相同的代码在SQLServer DB中工作没有问题)。
I found out, when your DB column has GUID (or UniqueIdentity) in SQLite and your model is nvarchar, SQLIte EF treats it as Binary(i.e., byte[]) by default. So when SQLite EF provider tries to convert GUID into the model (string in my case) it will fail as it will convert to byte[]. The fix is to tell the SQLite EF to treat GUID as TEXT (and therefore conversion is into strings, not byte[]) by defining "BinaryGUID=false;" in the connectionstring (or metadata, if you're using database first) like so:
<connectionStrings>
<add name="Entities" connectionString="metadata=res://savetyping...=System.Data.SQLite.EF6;provider connection string="data source=C:\...\db.sqlite3;Version=3;BinaryGUID=false;App=EntityFramework"" providerName="System.Data.EntityClient" />
</connectionStrings>
链接到对我有效的解决方案:
SQLite实体框架6提供者如何处理指南?
以下是我的后ria实体更新方法(Ef6时间框架):
public static void UpdateSegment(ISegment data)
{
if (data == null) throw new ArgumentNullException("The expected Segment data is not here.");
var context = GetContext();
var originalData = context.Segments.SingleOrDefault(i => i.SegmentId == data.SegmentId);
if (originalData == null) throw new NullReferenceException("The expected original Segment data is not here.");
FrameworkTypeUtility.SetProperties(data, originalData);
context.SaveChanges();
}
注意FrameworkTypeUtility.SetProperties()是我在NuGet上AutoMapper之前写的一个小工具函数:
public static void SetProperties<TIn, TOut>(TIn input, TOut output, ICollection<string> includedProperties)
where TIn : class
where TOut : class
{
if ((input == null) || (output == null)) return;
Type inType = input.GetType();
Type outType = output.GetType();
foreach (PropertyInfo info in inType.GetProperties())
{
PropertyInfo outfo = ((info != null) && info.CanRead)
? outType.GetProperty(info.Name, info.PropertyType)
: null;
if (outfo != null && outfo.CanWrite
&& (outfo.PropertyType.Equals(info.PropertyType)))
{
if ((includedProperties != null) && includedProperties.Contains(info.Name))
outfo.SetValue(output, info.GetValue(input, null), null);
else if (includedProperties == null)
outfo.SetValue(output, info.GetValue(input, null), null);
}
}
}