Я столкнулся с ошибкой, когда в некотором коде, основанном на EF6, изменения не обнаруживаются (хотя они сохраняются в хранилище данных).
При использовании свойства навигации List<Child>
изменения не обнаруживаются при изменении свойства в родительском объекте.EntityState остается неизменным.
Пример консольного приложения (.NET Framework 4.7.2 с NuGet EntityFramework 6.2) код:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Data.Entity;
using System.Data.Entity.ModelConfiguration;
using System.ComponentModel.DataAnnotations.Schema;
namespace EFStateTest
{
public class Tests
{
public static void Main()
{
var context = new StandaloneContext();
/* First time run, generate some test data to work with */
if (!context.Set<ParentTable>().Any())
{
ParentTable p = new ParentTable()
{
Data = "Foo",
Children = new List<ChildTable>()
{
new ChildTable()
{
ManyData = "Bar",
},
},
};
context.Set<ParentTable>().Add(p);
}
/* nth run, do the test */
else
{
var p = context.Set<ParentTable>().FirstOrDefault(); // Get our test record
p.Data = DateTime.Now.Ticks.ToString(); // Change some data
try
{
// Get the state
object d = p.GetType().GetField("_entityWrapper").GetValue(p);
System.Data.Entity.Core.Objects.ObjectStateEntry ose = d.GetType().GetProperty("ObjectStateEntry").GetValue(d) as System.Data.Entity.Core.Objects.ObjectStateEntry;
Console.WriteLine(ose.State);
}
catch
{
Console.WriteLine("Not a proxy class");
}
}
context.SaveChanges();
Console.WriteLine("DONE");
Console.ReadLine();
}
}
// Context
public class StandaloneContext : DbContext
{
public StandaloneContext() : base("Server=(local);Database=EFTest;Integrated Security=SSPI")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new ParentTableSchema());
modelBuilder.Configurations.Add(new ChildTableSchema());
base.OnModelCreating(modelBuilder);
}
}
public class ParentTable
{
public virtual int Id { get; set; }
public virtual string Data { get; set; }
public virtual List<ChildTable> Children { get; set; }
}
public class ChildTable
{
public virtual int Id { get; set; }
public virtual int ParentId { get; set; }
public virtual string ManyData { get; set; }
public virtual ParentTable Parent { get; set; }
}
public class ParentTableSchema : EntityTypeConfiguration<ParentTable>
{
public ParentTableSchema()
{
HasKey(m => m.Id)
.Property(m => m.Id)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
HasMany(m => m.Children)
.WithRequired(c => c.Parent)
.HasForeignKey(c => c.ParentId);
}
}
public class ChildTableSchema : EntityTypeConfiguration<ChildTable>
{
public ChildTableSchema()
{
HasKey(m => m.Id)
.Property(m => m.Id)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
}
}
}
Запустите один раз, чтобы сгенерировать базу данных на локальном компьютере, иеще раз, чтобы показать ошибку.Изменение свойства родительского объекта (p.Data = DateTime.Now.Ticks.ToString();
) не меняет отслеживаемое состояние объекта, я использую отражение, чтобы получить его здесь, но оно такое же, как при использовании ChangeTracker в контексте.
Теперь, если вы удалите коллекцию навигации для List<ChildTable> Children
, то проблема исчезнет (но я вроде хочу свойство навигации), и средство отслеживания изменений правильно изменится на Изменено.
У меня уже естьисправить, но это не отвечает почему .Измените свойство навигации, чтобы оно было определено как ICollection<ChildTable>
вместо List, IList и т. Д., И это также работает.
В документации, которую я до сих пор читал на EF, сказано, что в свойствах навигации необходимо реализовать ICollection - какой Listделает.Так что здесь дает?Я что-то не так делаю или что-то упускаю полностью?