首页 > 解决方案 > 如何使用 ASP.NET Core 2.1 Identity 在单个事务中添加新用户和声明?

问题描述

我正在尝试添加一个新用户和一些其他相关实体,包括作为一个交易的索赔。我的课程基本上定义如下。请注意,我int在我的类上使用主键,User并且它是一个标识列(值由数据库在插入时提供)。

public class User : IdentityUser<int>
{
    // custom props here
}

public class UserClaim : IdentityUserClaim<int>
{
    // i actually haven't added anything to this class, it's mainly here so 
    // i don't have to keep specifying the user's primary key type
}

public class OtherEntity 
{
    public int UserId { get; set; }

    [ForeignKey(nameof(UserId))]
    public User User { get; set; }

    // other stuff
}

然后我想将用户等添加到数据库中,如下所示:

User user = new User(){ /* set props */ };

OtherEntity other = new OtherEntity()
{
    User = user
};

UserClaim claim = new UserClaim()
{
    /* this is where the problem is */
    UserId = user.Id,
    ClaimType = "my-claim-type",
    ClaimValue = "my-claim-value"
};

context.AddRange(user, other, claim);
context.SaveChanges();

我可以轻松地将 链接User到 ,OtherEntity因为我已经设置了导航属性,所以我可以将 添加User到它,而实体框架会负责填充UserId列。我不能这样做,UserClaim因为它没有导航属性。我可以context.SaveChanges()在添加User实体框架后调用User.Id,我可以使用数据库为我创建的实体框架,我可以使用它来设置实体框架UserIdUserClaim但这意味着两个事务。

我尝试将导航属性添加到我的定义中UserClaim,如下所示:

public class UserClaim : IdentityUserClaim<int>
{
    [ForeignKey(nameof(UserId))]
    public User User { get; set; }
}

但我得到以下运行时错误:

InvalidOperationException:从 'UserClaim.User' 到 'User' 与外键属性 {'UserId' : int} 的关系不能以主键 {'Id' : int} 为目标,因为它不兼容。为此关系配置一个主键或一组兼容的外键属性。

有没有办法在同一个交易中同时创建用户和声明?

标签: asp.netentity-frameworkasp.net-identity

解决方案


实体框架中记录了插入相关数据:https ://docs.microsoft.com/pl-pl/ef/core/saving/related-data 并且在其他主题中也有很好的描述,例如:实体框架外键插入带自动 ID

每个实体都需要为实体模型中的关系(外键)正确设置(没有它们,EF 不知道该怎么做),当你添加它时,你需要从头开始,所以 UserClaim 必须是从您的用户实体设置,例如

    var user = new User(){
    //properites
    OtherEntity = new OtherEntity()
    {
        Id = 0, /*will be set automatically*/
        UserId = 0 /*will be set automatically*/
        /* other properites */
    };
    Claim = new UserClaim(){
        Id = 0, /*will be set automatically*/
        UserId = 0 /*will be set automatically*/
        /* other properites */
    }
}

ontext.Add(user);
context.SaveChanges();

您没有提供有关您的关系的所有信息,我只是从您的代码中假设了这一点。

PS。AddRange 只有一个参数。

编辑: 为了澄清我的答案,为了让一切正常工作,AddRange/Add 需要使用您的基本实体和内部关系以树状方式调用。但首先你需要配置你的模型,类似的东西。

public class User : IdentityUser<int>
{
    [ForeignKey("UserClaimId")]
    public virtual UserClaim Claim {get;set;}
}

public class UserClaim : IdentityUserClaim<int>
{
    [ForeignKey("UserId")]
    public virtual User User {get;set;}
}

public class OtherEntity 
{
    public int UserId { get; set; }

    [ForeignKey("UserId")]
    public User User { get; set; }

    // other stuff
}

您还可以使用 OnModelCreating 设置实体,如文档中所述:https ://docs.microsoft.com/en-us/ef/core/modeling/relationships

实体框架现在对数据库中的关系、数据类型等一无所知。

更新的代码示例

编辑,没有足够的声誉来为您的答案添加评论

好吧,EF 仍然需要跟踪实体。我需要编写并运行一些示例来检查是否有某种方法可以改善对数据库的访问。也许有人可以告诉您更多关于添加相关数据背后的机制以及是否有改进它的方法。有一些库有助于提高保存数据库更改的性能,例如:https ://entityframework-extensions.net 你可以试试。


推荐阅读