簡體   English   中英

實體框架模型生成奇怪的錯誤消息

[英]Entity framework model generating weird error message

我有一個PostgreSql 9.04數據庫,其中包含ASPNet Membership Services數據庫的postgres實現。 此實現與我自己的表位於同一數據庫中,但位於稱為“安全”的不同架構中。

由於業務原因,我在實體模型中包含了aspnet_Users,aspnet_Membership和aspnet_Profiles表。 下面是這些表的DDL。

CREATE TABLE security.aspnet_users (
    userid UUID NOT NULL,
    applicationname VARCHAR(255) NOT NULL,
    username VARCHAR(255),
    lastactivitydate TIMESTAMP,
    isanonymous INT,
    CONSTRAINT aspnet_users_userid_pk PRIMARY KEY (userid),
    CONSTRAINT aspnet_users_username_pk UNIQUE (username, applicationname)
);

CREATE TABLE security.aspnet_membership (
    userid UUID NOT NULL,
    password VARCHAR(255),
    passwordsalt VARCHAR(255),
    passwordformat INT,
    email VARCHAR(255),
    passwordquestion VARCHAR(255),
    passwordanswer VARCHAR(255),
    comments VARCHAR(255),
    isapproved INT,
    islockedout INT,
    creationdate TIMESTAMP,
    lastlogindate TIMESTAMP,
    lastpasswordchangeddate TIMESTAMP,
    lastlockoutdate TIMESTAMP,
    failedpasswordattemptcount INT,
    failedpasswordattemptstart TIMESTAMP,
    failedpasswordanswercount INT,
    failedpasswordanswerstart TIMESTAMP,

    CONSTRAINT aspnet_membership_userid_pk PRIMARY KEY (userid),
    CONSTRAINT aspnet_membership_userid_ref FOREIGN KEY (userid) REFERENCES security.aspnet_users (userid)
);

CREATE TABLE security.aspnet_profiles (
    userid                      UUID,
    propertynames               BYTEA NOT NULL,
    propertyvaluesstring        BYTEA NOT NULL,
    propertyvaluesbinary        BYTEA NULL,
    lastupdateddate             TIMESTAMP NOT NULL,

    CONSTRAINT aspnet_profiles_userid_ref FOREIGN KEY (userid) REFERENCES security.aspnet_users (userid),
    CONSTRAINT aspnet_profiles_userid_key UNIQUE (userid)
);

同樣,這些是該模式中模型中僅有的表。

現在,當我在這些表中插入一行並調用SaveChanges時,出現以下錯誤消息:

無法確定“ Membership_Users”關系的主要結尾。 多個添加的實體可能具有相同的主鍵。

以下是我用於插入新行或更新現有行的代碼示例。 這代表了我正在執行的有關更新數據庫的所有操作。

public static void SaveUserProfile( CarSystemEntities context, UserProfileData data ) {
    if ( context == null )
        throw new ArgumentNullException( "context", "You must pass a non-null CarSystemEntities instance." );

    if ( data == null )
        throw new ArgumentNullException( "data", "You must pass a non-null UserProfileData instance." );

    try {
        Profile profile = null;

        if ( !context.Profiles.Any( p => p.Userid == data.ID ) ) {
            profile = new CarSystem.Profile{
                LastUpdatedDate      = data.LastUpdatedDate.LocalDateTime,
                PropertyNames        = data.PropertyNames, 
                PropertyValuesBinary = data.PropertyValuesBinary, 
                PropertyValuesString = data.PropertyValuesString,
                Userid               = data.ID
            };

            context.Profiles.AddObject( profile );
        } else {
            profile = QueryUerProfiles( context ).Where( p => p.Userid == data.ID ).Single();

            if ( profile.LastUpdatedDate      != data.LastUpdatedDate )      profile.LastUpdatedDate      = data.LastUpdatedDate.LocalDateTime;
            if ( profile.PropertyNames        != data.PropertyNames )        profile.PropertyNames        = data.PropertyNames;
            if ( profile.PropertyValuesBinary != data.PropertyValuesBinary ) profile.PropertyValuesBinary = data.PropertyValuesBinary;
            if ( profile.PropertyValuesString != data.PropertyValuesString ) profile.PropertyValuesString = data.PropertyValuesString;
        }

    } catch ( Exception ex ) {
        throw new DataAccessException( DataAccessOperation.SaveProfile, FailureReason.DatabaseError, ex );
    }
}

此錯誤的原因是什么? 我該如何解決?

謝謝

托尼

聚苯乙烯

經過進一步研究,問題不在於插入行,而是在於嘗試在與插入行的事務相同的事務中更新行。

本質上,存在要寫入數據庫的對象隊列。 依次從隊列中刪除每個對象,並調用類似於上述對象的方法將其保存到正確的表中。

第一次看到特定ID時,該方法將其插入。 也就是說,Any檢查返回false。 該代碼創建新的實體對象,並為與該表相對應的實體集調用AddObject方法。 到現在為止還挺好。

此后,假定Any檢查將返回true,表示已經存在具有給定ID的行。 然后應該更新該行。 但是,即使我在與第一次調用的表相對應的實體集上調用了AddObject,似乎Any檢查也第二次返回false。

知道我在做什么錯嗎?

PPS

我在打開Sql監視器的情況下進行了更多測試。 我們正在使用Devart dotConnect for PostgreSql庫,他們有一個可以下載的名為DbMonitor的工具。 這使您可以跟蹤由實體框架發出和執行的SQL。

事實證明,對.Any的調用會作為對數據庫的查詢立即執行(發生時是可預測的),而一旦您調用SaveChanges,所有插入都將排隊並應用。 Any調用似乎並沒有考慮任何等待插入的行,只是數據庫調用返回的行。 由於尚未插入要插入的行,因此該查詢將始終返回false,直到調用SaveChanges。

結果,我目前的邏輯將無法正常工作。 當等待插入的行被更新時(也就是說,它再次出現在隊列中),插入邏輯將再次運行。 有時,我會收到一個異常,指示違反了唯一鍵或主鍵約束,而其他時候,我會得到最初發布的消息。

我需要在單個事務中完成所有插入和更新,並且需要在調用AddObject時在數據庫中進行插入。 但是,如果在插入或更新單行時出錯,或者C#代碼中發生其他錯誤,我仍然需要所有插入和更新來回滾。

有人對我如何使用實體框架做到這一點有任何想法嗎?

似乎您要添加到數據庫的Profile對象上沒有設置主鍵。 Guid的默認值為Guid.Empty,因此第一個被保存,但隨后的每個對象均失敗。

下面的代碼設置主鍵

if ( !context.Profiles.Any( p => p.Userid == data.ID ) ) {
            profile = new CarSystem.Profile{
                LastUpdatedDate      = data.LastUpdatedDate.LocalDateTime,
                PropertyNames        = data.PropertyNames, 
                PropertyValuesBinary = data.PropertyValuesBinary, 
                PropertyValuesString = data.PropertyValuesString,
                Userid               = data.ID

                //add the next line to ensure there is a pk field
                ID                   = Guid.NewGuid()
            };

我設法解決了這個問題,希望它能起作用。

起初我所有問題的原因是實體框架一直等到您調用SaveChanges將任何更改寫入數據庫。 但是,當您執行.Any()調用時,將立即生成並執行SQL,而忽略任何等待寫入數據庫的更改。 所以我的代碼始終認為,即使其中一個是真正的插入而另一個應該是更新,也必須插入新行。

接下來,我嘗試使用TransactionScope對象,在插入或更新每個對象后調用SaveChanges()。 然后,我將調用TransactionScope實例的Completed()方法來“提交”更改。 好吧,低估了,這最終的工作原理與等待調用SaveChanges時完全相同! 除非調用scope.Completed(),否則什么都不會寫入數據庫。

我發現可行的解決方案如下代碼所示:

using ( CarSystemEntities context = new CarSystemEntities() ) { 
    if ( context.Connection.State != ConnectionState.Open ) { 
        context.Connection.Open(); 
    } 

    DbTransaction transaction = context.Connection.BeginTransaction(); 

    try { 
        <Data processing code here> 

        transaction.Commit(); 

    } catch ( Exception ex ) { 
        transaction.Rollback(); 

        <More exception code here as needed> 
    }             
}

結合在每個context..AddObject或屬性更新之后調用SaveChanges,一切都按我需要的方式工作。 調用SaveChanges時,將生成並執行INSERT&Update語句。 對.Any的調用還考慮了上一次迭代插入表中的任何行。 一切都在一個實際的數據庫事務中,該事務可以作為整體提交或回滾。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM