Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/290.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 实体框架模型生成错误消息_C#_Postgresql_Entity Framework 4 - Fatal编程技术网

C# 实体框架模型生成错误消息

C# 实体框架模型生成错误消息,c#,postgresql,entity-framework-4,C#,Postgresql,Entity Framework 4,我有一个PostgreSql 9.04数据库,其中包含一个ASPNet会员服务数据库的postgres实现。此实现与我自己的表位于同一个数据库中,但位于称为“安全性”的不同模式中 出于业务原因,我在实体模型中包括了aspnet_用户、aspnet_成员资格和aspnet_配置文件表。下面是这些表的DDL CREATE TABLE security.aspnet_users ( userid UUID NOT NULL, applicationname VARCHAR(255) N

我有一个PostgreSql 9.04数据库,其中包含一个ASPNet会员服务数据库的postgres实现。此实现与我自己的表位于同一个数据库中,但位于称为“安全性”的不同模式中

出于业务原因,我在实体模型中包括了aspnet_用户、aspnet_成员资格和aspnet_配置文件表。下面是这些表的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时,会收到以下错误消息:

无法确定“成员资格\用户”关系的主体端。多个添加的实体可能具有相同的主键

下面是我用来插入新行或更新现有行的代码示例。这代表了我在更新数据库方面所做的一切

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。然后应该更新该行。但第二次Any检查似乎也返回false,即使我在第一次调用时调用了对应于表的实体集上的AddObject

知道我做错了什么吗

PPS

我在Sql监视器打开的情况下做了更多的测试。我们正在使用Devart dotConnect for PostgreSql库,他们有一个工具,您可以下载,名为DbMonitor。这允许您跟踪实体框架发出和执行的SQL

事实证明(可以预见,正如它所发生的那样),对.Any的调用会作为对数据库的查询立即执行,而所有插入都会排队并在调用SaveChanges后应用。Any调用似乎不考虑任何挂起插入的行,而只考虑数据库调用返回的行。由于要插入的行尚未插入,因此在调用SaveChanges之前,此查询将始终返回false

因此,我目前的逻辑是行不通的。当更新挂起插入的行时(即,它在队列中再次出现),插入逻辑将再次运行。有时我会收到一个异常,表明违反了唯一或主键约束,而有时我会收到我最初发布的消息

我需要在单个事务中完成所有插入和更新,并且需要在调用AddObject时在数据库中进行插入。但是,如果插入或更新一行出错,或者如果C代码中发生其他错误,我仍然需要所有的插入和更新来回滚


有人知道我如何使用实体框架实现这一点吗?

看起来主键并没有设置在要添加到数据库的概要文件对象上。Guid的默认值为Guid.Empty,因此会保存第一个Guid,但随后的每个对象都会失败

下面的代码设置主键

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()
            };

看起来主键并没有在要添加到db的概要文件对象上设置。Guid的默认值为Guid.Empty,因此会保存第一个Guid,但随后的每个对象都会失败

下面的代码设置主键

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> 
    }             
}
使用(CarSystemEntities context=new CarSystemEntities()){
如果(context.Connection.State!=ConnectionState.Open){
context.Connection.Open();
} 
DbTransaction=context.Connection.BeginTransaction();
试试{
Commit();
}捕获(例外情况除外){
transaction.Rollback();
}             
}

再加上在每次上下文..AddObject或属性更新后调用SaveChanges,所有操作都完全按照我需要的方式进行。调用SaveChanges时,将生成并执行INSERT&Update语句。对.Any的调用还考虑了上一次迭代插入到表中的任何行。所有内容都在一个真正的数据库事务中,可以作为一个整体提交或回滚。

我已经设法以我希望的方式解决了这个问题

起初,我所有问题的原因都是实体框架等待您调用SaveChanges