【问题标题】:Loaded from another DataContext?从另一个 DataContext 加载?
【发布时间】:2012-03-20 13:33:52
【问题描述】:

在我以前使用 linq-to-sql 的应用程序中,我总是使用一个类来放入我的 linq-to-sql 代码,所以我只有一个 DataContext

我当前的应用程序变得太大,我开始将我的代码分成不同的类(一个用于客户,一个用于位置,一个用于供应商......)并且它们都有自己的 DataContext DatabaseDesignDataContext dc = new DatabaseDesignDataContext();

现在,当我尝试使用某个位置(我从不同的 DataContext 获得)保存联系人时,我收到以下错误:

“已尝试附加或添加一个不是新的实体,可能是从另一个 DataContext 加载的。不支持。”

我认为这是因为我为每个班级创建了一个DataContext,但我不知道如何以不同的方式做到这一点?

我正在寻找任何想法,谢谢。

我的课程如下所示:

 public class LocatieManagement
{
    private static DatabaseDesignDataContext dc = new DatabaseDesignDataContext();

    public static void addLocatie(locatie nieuweLocatie)
    {
        dc.locaties.InsertOnSubmit(nieuweLocatie);
        dc.SubmitChanges();
    }

    public static IEnumerable<locatie> getLocaties()
    {
        var query = (from l in dc.locaties
                     select l);
        IEnumerable<locatie> locaties = query;

        return locaties;
    }

    public static locatie getLocatie(int locatie_id)
    {
        var query = (from l in dc.locaties
                     where l.locatie_id == locatie_id
                     select l).Single();

        locatie locatie = query;
        return locatie;

    }
}

【问题讨论】:

    标签: c# winforms linq-to-sql datacontext


    【解决方案1】:

    如果实体仍附加到原始数据上下文,则会发生这种情况。关闭延迟加载(dc.DeferredLoadingEnabled = false):

    partial class SomeDataContext
    {
        partial void OnCreated()
        {
            this.DeferredLoadingEnabled = false;
        }
    }
    

    您可能还需要对其进行一次序列化/反序列化(例如使用 datacontractserializer)以将其与原始 DC 断开连接,这是使用 datacontractserializer 的克隆方法:

    internal static T CloneEntity<T>(T originalEntity) where T : someentitybaseclass
    {
        Type entityType = typeof(T);
    
        DataContractSerializer ser =
            new DataContractSerializer(entityType);
    
        using (MemoryStream ms = new MemoryStream())
        {
            ser.WriteObject(ms, originalEntity);
            ms.Position = 0;
            return (T)ser.ReadObject(ms);
        }
    }
    

    【讨论】:

    • 我必须在每个类中关闭延迟加载吗?谢谢。
    • 如果你不使用延迟加载/延迟加载,你可以通过将它添加到数据上下文的 OnCreated...这个)
    【解决方案2】:

    发生这种情况是因为您尝试管理来自不同上下文的数据 - 您需要正确分离和附加对象才能继续 - 但是,我建议您避免这样做。

    所以,首先要做的是:从您的实体类中删除数据上下文实例

    从这里创建“操作”类,这些类公开 CRUD 和其他与特定类型的实体类一起使用的东西,每个函数使用该工作单元的专用数据上下文,可能会重载到当一个工作单元需要后续操作时,接受当前上下文。

    【讨论】:

    • 我不确定我是否理解您所说的操作类是什么意思。我用一个类的例子更新了我的第一篇文章。你的意思是我应该使用继承之类的东西吗?感谢您的帮助!
    • 抱歉术语混乱,但实践就像贾斯汀建议的那样:使用 repo 模式,repos 接受和返回实体类型,去 db 获取它们(或从如果你的仓库实现了这样的东西,则缓存)并一举设置它们,最后关闭数据上下文。
    • 我明白了,可悲的是,我真的不知道该怎么做。我以前从未使用过接口或回购模式。 (我还在学习中)我会试着研究一下,谢谢。 :)
    【解决方案3】:

    我知道每个人可能已经厌倦了听到这个,但您确实应该考虑使用存储库进行数据访问(并使用工作单元模式来确保共享一个工作单元的所有存储库都使用相同的数据上下文)。

    您可以在此处阅读如何做事:Revisiting the Repository and Unit of Work Patterns with Entity Framework(同样的概念也适用于 LINQ to SQL)。

    【讨论】:

    • 谢谢,我对接口/存储库不是很熟悉,我会尝试阅读您提供的链接。
    • 这个答案是“去读点别的”——一个美化的链接唯一的答案。它不直接提供任何有用的信息。
    【解决方案4】:

    为此我找到的另一种解决方案是创建一个父类DataContext

    public class DataContext
    {
        public static DatabaseDesignDataContext dc = new DatabaseDesignDataContext();
    }
    

    让我所有的其他类继承这个。

     public class LocatieManagement : DataContext
     {
            public static void addLocatie(locatie nieuweLocatie)
            {
                dc.locaties.InsertOnSubmit(nieuweLocatie);
                dc.SubmitChanges();
            }
     }
    

    那么所有的类都使用相同的DataContext。

    【讨论】:

    • 如果您想做任何事务处理(您应该这样做),这是一个坏主意。此外,如果使用多个线程或者它是一个 Web 应用程序,当多个线程尝试使用相同的数据上下文时,您会遇到问题。这也可以防止同时使用多个数据库连接,因此一切都依赖于同一个连接。
    • 谢谢,不过我不知道什么是事务处理。你会如何解决这个问题?
    • 我的意思是你应该创建一个新的 DataContext 并在执行一些工作时使用它。然后摆脱它(在using (MyDataContext dc = new MyDataContext()) 块中做你的工作)。不要使用全局数据上下文——你需要做的每件“事情”都需要一个新的上下文。例如,如果您正在为网页加载数据,请为该页面视图使用单个数据上下文。如果您正在执行一个多步骤操作,其中所有步骤都相互关联并相互依赖,那么也可以为整个过程使用单个数据上下文。希望这会有所帮助!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-08-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-31
    相关资源
    最近更新 更多