【问题标题】:Storing list of custom objects in Entity Framework在实体框架中存储自定义对象列表
【发布时间】:2017-11-17 14:32:11
【问题描述】:

开始学习 asp.net 和 DB 操作。尝试实现一些简单的功能 - 两个模型,一个具有对另一个的引用列表。

这是我目前得到的一个错误:

初始化数据库时发生异常。有关详细信息,请参阅 InnerException。

内部异常:
无法确定相关操作的有效排序。由于外键约束、模型要求或存储生成的值,可能存在依赖关系。

我的模型:

public class Killer
{
        public Killer(string name, string biography)
        {
            Name = name;
            Biography = biography;
            KillerId = Guid.NewGuid();
        }

        public Guid KillerId { get; set; }
        public string Name { get; set; }
        public string Biography { get; set; }

        public virtual Contract Contract { get; set; }
}

public class Contract
{
        public Contract(Status status, Killer target, string description, params Killer[] targets)
        {
            ContractId = Guid.NewGuid();
            this.status = status;
            Target = target;
            Description = description;

            Killers = new HashSet<Killer>();
            foreach (var t in targets) Killers.Add(t);

        }

        public Guid ContractId { get; set; }

        public enum Status { active, done, failed, rejected, abandoned }
        public Status status { get; set; }

        public Killer Target { get; set; }
        public string Description { get; set; }

        //[ForeignKey("ContractID")]
        public virtual ICollection<Killer> Killers { get; set; }
}

在上下文中,我使用对象列表初始化 db

public class KillerContext : DbContext
{
    public DbSet<Killer> Killers { get; set; }
    public DbSet<Contract> Contracts { get; set; }
}

在控制器中我这样做:

KillerContext k = new KillerContext();

public ActionResult Index()
{
    var contracts = k.Contracts.ToList();
    ViewBag.contracts = contracts;
    return View();
}

Global.asax

Database.SetInitializer(new KillerContextInitialization());

这是我在 db 中输入第一个数据的方式:

public sealed class KillerContextInitialization : DropCreateDatabaseAlways<KillerContext>
{
    protected override void Seed(KillerContext db)
    {
        List<Killer> killers = new List<Killer>();
        //List<Contract> contracts = new List<Contract>();

        killers.Add(new Killer(name: "Ivan Firstein", biography: "He was born in the shadows."));
        killers.Add(new Killer(name: "Oleg Gazmanov", biography: "test man"));
        db.Contracts.Add(new Contract(
                Contract.Status.active,
                killers.SingleOrDefault(x => x.Name == "Ivan Firstein"),
                "KILL OR BE KILLED. As always with love.",
                killers.SingleOrDefault(x => x.Name == "Oleg Gazmanov")
                ));

        db.Killers.AddRange(killers);
        base.Seed(db);
    }
}

【问题讨论】:

  • 这是代码优先还是数据库优先?
  • 代码优先。是根据一些关于实体框架的文章完成的

标签: c# sql-server asp.net-mvc entity-framework


【解决方案1】:

看起来您需要为杀手模型添加 ForeignKey 属性,并将此键存储在属性 ContractId 中:

public class Killer
{
    [ForeignKey(nameof(ContractId)]  //Name of added property in line below
    public Contract Contract { get; set; } //no need "virtual"
    public Guid? ContractId { get; set; }

    // other properties...
}

public class Contract
{
        [ForeignKey("ContractId")] //Name of added property in Killer Model
        public virtual ICollection<Killer> Killers { get; set; }

        // other code... 
}

编辑

您应该执行类似于 Contract.Target 属性的操作:

[ForeignKey(nameof(TargetId)]
public Killer Target { get; set; }
public Guid TargetId { get; set; }

对于枚举类型,您应该添加如下属性:

[Column(nameof(status), TypeName = "int")]
public Status status { get; set; }

【讨论】:

  • 仍然有同样的错误......它出现在 Index() 时投射 .ToList();同样生成的数据库中没有数据
【解决方案2】:

发现问题出在public Killer Target { get; set; } 当我添加数据时,该字段被视为NOT NULL,我需要做的就是在填充杀手后保存更改,如下所示:

 public sealed class KillerContextInitialization : DropCreateDatabaseAlways<KillerContext>
    {
        protected override void Seed(KillerContext db)
        {
            List<Killer> killers = new List<Killer>();


            killers.Add(new Killer(name: "Ivan Firstein", biography: "He was born in the shadows."));
            killers.Add(new Killer(name: "Oleg Gazmanov", biography: "test man"));

            db.SaveChanges(); // - save killers first, then add them to contract
            db.Contracts.Add(new Contract(
                    Contract.Status.active,
                    killers.SingleOrDefault(x => x.Name == "Ivan Firstein"),
                    "KILL OR BE KILLED. As always with love.",
                    killers.SingleOrDefault(x => x.Name == "Oleg Gazmanov")
                    ));

            db.Killers.AddRange(killers);
            base.Seed(db);
        }
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多