2

我目前遇到了一个问题,我搜索了堆栈溢出的高低,似乎没有解决方案。我觉得我一定做错了什么,但希望有人能帮忙。

无论如何,我有以下型号:

public abstract class IDObject
{
    [Key]
    public Guid ID { get; set; }
}

public class TV : IDObject
{
    public TV()
    {
        this.Channels = new List<Channel>();
    }
    public string Name { get; set; }
    public virtual IList<Channel> Channels { get; set; } 
}

public class Channel : IDObject
{
    public string Name { get; set; }
    public int Number { get; set; }
    [Navigational]
    public virtual IList<TV> TVs { get; set; }  
}

电视 - 频道应该是多对多的关系。

现在基本上我希望能够将电视和频道添加到数据库中,处理上下文,让电视引用之前添加的频道,然后更新数据库实体。

就像是:

TV someTV = new TV() { ID = Guid.NewGuid(), Name = "myBigTV" };
Channel chan1 = new Channel() { ID = Guid.NewGuid(), Name = "CBC", Number = 3};

using (ReferenceContext context = new ReferenceContext())
{
    context.TVs.Add(someTV);
    context.Channels.Add(chan1);
    context.SaveChanges();
}

someTV.Name = "myBigTV updated";
someTV.Channels.Add(chan1);

using (ReferenceContext context = new ReferenceContext())
{
    context.TVs.Attach(someTV);
    context.Entry(someTV).State = EntityState.Modified;
    *** some code here ***
    context.SaveChanges();
}

当我这样做时,我的 someTV 实体会更新,但是当我在数据库中进行“查找”调用时,它仍然没有对 Channels 的引用。

现在我已经在 DbCollectionEntry 上为 Channels 尝试了 .Load()。我尝试在上下文中从 someTV 中删除所有对频道的引用,然后重新添加它们。我尝试将我从 someTV 引用的频道上的 EntityState 更改为 Modified ......似乎没有任何效果。

我首先使用代码,数据库正在为我创建以下表格:

Channels
ChannelTVs
TVs

频道和电视看起来都不错,但无论我做什么,我的连接表“ChannelTVs”总是空的。

问题一:在这种情况下更新关联的标准方法是什么。我不需要自己更新频道,只需从连接表中添加/删除实体即可。我是否需要向 fluent API 添加一些内容来为我获取这些更改?

问题二:有没有办法以通用的方式做到这一点?我当前的更新看起来像:

void Update<TDatabase>(IDatabaseContext context, TDatabase item)
{
    IDbSet<TDatabase> dbSet = context.GetDbSet<TDatabase>();
    dbSet.Attach(item);
    context.Entry(item).State = EntityState.Modified;
    context.SaveChanges();
}

我知道以前有人问过这样的问题,但似乎没有一个解决方案有效。这可能是我做错了什么,或者只是一个特殊情况......

谢谢。

4

1 回答 1

0

如果有人发现这个并且很好奇......我设法找到了一个通用的解决方案。虽然不漂亮,但它确实有效。

update()
{
    using (ReferenceContext context = new ReferenceContext())
    {
        TV newTV = context.TVs.Single(x => x.ID == someTV.ID);
        DbEntityEntry entityEntry = context.Entry(newTV);
        entityEntry.CurrentValues.SetValues(someTV);
        UpdateReferences(context, entityEntry, someTV);
        context.SaveChanges();
    }
}

private static void UpdateReferences(ReferenceContext context, DbEntityEntry entityEntry, IDObject someObject)
{
    List<PropertyInfo> properties = someObject.GetType().GetProperties().Where(prop => !prop.IsDefined(typeof(NavigationalAttribute), false) && prop.PropertyType.GetInterfaces().Any(type => type == typeof(IEnumerable)) && prop.PropertyType.GetGenericArguments().Any()).ToList();

    foreach (PropertyInfo property in properties)
    {
        IList references = (IList)property.GetValue(someObject, null);
        DbCollectionEntry newCollection = entityEntry.Collection(property.Name);


        var method = typeof(TestEF).GetMethod("Wrapped", BindingFlags.NonPublic | BindingFlags.Static).MakeGenericMethod(property.PropertyType.GetGenericArguments()[0]);

        method.Invoke(null, new object[] { context, newCollection.CurrentValue, references });
    }
}

private static void Wrapped<T>(ReferenceContext context, IList<T> container, IEnumerable<T> references) where T : IDObject
{
    container.Clear();
    var dbSet = context.GetDbSet<T>();
    foreach (var referencedObject in references)
    {
        T item = dbSet.Find(referencedObject.ID);
        container.Add(item);
    }
}
于 2013-04-24T14:11:41.067 回答