简体   繁体   English

代码第一外键关联MVC实体

[英]Code first foreign key association MVC Entity

I have an Html sanitizer (more like an xss detector) code I'm working on and would like to log failures caused during code xss sanitation/detection. 我有一个Html清理程序(更像是一个xss检测器)我正在处理的代码,并希望记录代码xss卫生/检测过程中引起的故障。 So in entity, I have the following model for my UserProfile 所以在实体中,我的UserProfile有以下模型

[Table("UserProfile")]
public class UserProfile
{
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int UserId { get; set; }
    public string UserName { get; set; }
    public virtual List<Security> SecurityViolations { get; set; } //is this correct???
}

and for my security class model, I have the following: 对于我的安全类模型,我有以下内容:

[Table("Security")]
public class Security
{
    [Key]
    public int Id { get; set; }
    [Required]
    public string SecMsg { get; set; }
    public string Trace { get; set; }
    public int ErrorCode{ get; set; }
    public int UserId { get; set; } 
    public virtual UserProfile UserProfile { get; set; } 
}

To clarify my idea, when a security failure happens, the Security model is filled in with information but I like to tie all that information to the user that generated the errors so I establish a foreign key relation (or try to at least), to the UserProfile UserId primary key column. 为了澄清我的想法,当安全性失败发生时,安全模型充满了信息,但我喜欢将所有信息绑定到生成错误的用户,因此我建立了一个外键关系(或至少尝试), UserProfile UserId主键列。

Therefore, the code to log to my Security table is as follows: 因此,登录到我的安全表的代码如下:

using (CCSecurity sec_db = new CCSecurity())
            {
                Security sec_execption = new Security();
                sec_execption.SecMsg = ex.Message;
                sec_execption.Trace = ex.StackTrace;
                sec_execption.UserId = uid;  //uid is 12, a PK entry in UserProfile
                try
                {
                    sec_db.Security.Add(sec_execption);
                    sec_db.SaveChanges();
                }
                catch (Exception e)
                {
                    Debug.WriteLine(e.StackTrace.ToString());
                }

            }

So then during one of my unit test execution, I get the following exception: 那么在我的一个单元测试执行期间,我得到以下异常:

"The property 'UserId' cannot be configured as a navigation property. The property must be a valid entity type and the property should have a non-abstract getter and setter. For collection properties the type must implement ICollection where T is a valid..." “属性'UserId'不能配置为导航属性。属性必须是有效的实体类型,属性应该具有非抽象的getter和setter。对于集合属性,类型必须实现ICollection,其中T是有效的.. “。

I'm new to entity and googling the above turned many suggestion that did not solve my problem. 我是实体的新手,谷歌搜索上面的许多建议并没有解决我的问题。 How can I have a foreign key in my Security class that references a primary key in my UserProfile class and still have it well documented in code (ie the ForeignKey property field denotes foreign key in Security class) ? 如何在我的Security类中引用一个外键,该外键引用我的UserProfile类中的主键并且仍然在代码中有详细记录(即ForeignKey属性字段表示Security类中的外键)?

Edit: 编辑:

public class CCSecurity : DbContext
{
    public DbSet<Security> Security { get; set; }
    public CCSecurity()
        : base("TBCdb")
    {}
}

Edit 2 编辑2

The auto migration generated the Security Table as follow's: 自动迁移生成安全表如下:

CREATE TABLE [dbo].[Security] (
[Id]        INT            IDENTITY (1, 1) NOT NULL,
[SecMsg]    NVARCHAR (MAX) NOT NULL,
[Trace]     NVARCHAR (MAX) NULL,
[ErrorCode] INT            NOT NULL,
[UserId]    INT            NOT NULL,
CONSTRAINT [PK_dbo.Security] PRIMARY KEY CLUSTERED ([Id] ASC),
CONSTRAINT [FK_dbo.Security_dbo.UserProfile_UserId] FOREIGN KEY ([UserId]) REFERENCES [dbo].[UserProfile] ([UserId]) ON DELETE CASCADE

); );

Seem ok but it throws the error on SaveChanges(): 似乎没问题,但它会在SaveChanges()上抛出错误:

"The INSERT statement conflicted with the FOREIGN KEY constraint "FK_dbo.Security_dbo.UserProfile_UserId". The conflict occurred in database \\"TBCdb\\", table \\"dbo.UserProfile\\", column 'UserId'.\\r\\nThe statement has been terminated." “INSERT语句与FOREIGN KEY约束冲突”FK_dbo.Security_dbo.UserProfile_UserId“。冲突发生在数据库\\”TBCdb \\“,table \\”dbo.UserProfile \\“,列'UserId'。\\ r \\ n语句已被删除终止“。

在此输入图像描述

Latest Edit So I started a new project console app to test if something weird is happening on my main project. 最新编辑所以我开始了一个新的项目控制台应用程序,以测试我的主项目是否发生了奇怪的事情。 I basically copied my two models in the new project (Security and UserProfile) and got it to work... I'm using a file db and don't know what could be wrong in my main project and what can be different in the new console app project. 我基本上在新项目中复制了我的两个模型(Security和UserProfile)并让它工作......我正在使用文件数据库而不知道我的主项目中可能出现什么问题以及可能有什么不同之处新的控制台应用项目。 I'm running a Unit Test on my main project and I wonder if that has anything to do with it. 我在我的主项目上运行单元测试,我想知道它是否与它有关。

Thanks! 谢谢!

As the error message indicates, your foreign key needs to be associated with a valid entity property. 如错误消息所示,您的外键需要与有效的实体属性相关联。 So, instead of declaring the foreign key as follows: 因此,而不是如下声明外键:

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

You need to declare it as: 您需要将其声明为:

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

You don't need UserId property, just remove it and use UserProfile. 您不需要UserId属性,只需删除它并使用UserProfile。 Entity Framework will handle this automatically. 实体框架将自动处理此问题。

sec_execption.UserProfile = getUserProfileById(uid);

getUserProfileById might look like: getUserProfileById可能如下所示:

return sec_db.UserProfiles.Where(u => u.UserId == uid).FirstOrDefault();

PS PS

public virtual List<Security> SecurityViolations { get; set; } // is ok

but

public virtual ICollection<Security> SecurityViolations { get; set; } // is better

Try it like below to have one-to-many relationship between Users and Securtiy. 尝试如下,在用户和Securtiy之间建立一对多的关系。 As mentioned below virtual keyword is all required to indicate to EF a relationship between entities. 如下所述, 虚拟关键字都需要向EF指示实体之间的关系。

public class Security
{
    public int Id { get; set; }
    public string SecMsg { get; set; }
    public string Trace { get; set; }
    public int ErrorCode { get; set; }

    public int UserId { get; set; } //This is just to tell EF to name the FK column as UserId rather than UserProfile_UserId

    public virtual UserProfile UserProfile { get; set; } //This is good enough to tell EF that there is a relationship
}

public class UserProfile
{
    [Key]
    public int UserId { get; set; }
    public string UserName { get; set; }

    public virtual ICollection<Security> Securities { get; set; } //Good enough to indicate the relationship
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM