zoukankan      html  css  js  c++  java
  • Entity Framework with MySQL 学习笔记一(关系整理版)

    1-1 设置

       //DataAnnotation 1-1 | 1-0 table 
        //SQLtable : member , columns : memberId, name
        //SQL basic logic : 1个table的PK, 是另一个table的PK and FK , 这就是1-1和1-0的关系
        [Table("member")]
        public class Member
        {
            [Key]
            public Int32 memberId { get; set; }
            public string name { get; set; }
            [Required]
            /*        
                1-0,这里就不要Required
                1-1关系最好是放Required啦,在insert的时候才不会出错,但是... 
                如果你写Required,那么你在做update的时候这个address不能是Null,也就是说一定要inner join出来先,不是很方便.        
            */
            public virtual Address address { get; set; }
        }
        //SQLtable : address , columns : memberId, postcode, country
        [Table("address")]
        public class Address
        {
            /*
                关键就是这个关系连接, "member" 是 tableName
            */
            [Key, ForeignKey("member")] //foreignKey 一定要写在这里,不可以写在 Member 哦
            public Int32 addressId { get; set; } //这里取名addressId也行
            public string postcode { get; set; }
            public string country { get; set; }
            public virtual Member member { get; set; }
        }

    注 : ForeignKey("member") 的member 是取至于 virtual Member "member" , 这2个要一直

    基本的 CRUD

    using (EFDB db = new EFDB())
    {
        /*insert*/
        db.members.Add(new Member
        {
            name = "keatkeat",
            address = new Address
            {
                postcode = "81300",
                country = "malaysia"
            }
        });
        db.SaveChanges();
    
        /*select*/
        var members = db.members.Include(m => m.address).ToList(); //要include才会一起出来哦 
             
        /*update*/
        var member = db.members.Include(m => m.address).First().name = "xinyao123";
        db.SaveChanges();
    
        /*delete*/
        db.members.Remove(db.members.Include(m => m.address).First()); //要include出来才能一次删除2个table的数据!
        db.SaveChanges();
    }
    View Code

    这里有一个要注意的 : 

    如果 A 和 B 是 1-1 关系, 而 B 是一抽象类 C,D 是B的派生类,那么当我们想要替换掉 C 时,我们并不能单纯的 a.b = new D() 

    我们也不可以先删除再添加  

    db.Bs.remove(a.b);

    a.b = new D(); 

    我们必须使用 transaction, SaveChanges 2 次,

    transaction.open();

    db.Bs.remove(a.b);

    db.SaveChanges();

    a.b = new D();

    db.SaveChanges();

    transaction.commit();

    这样才可以!

    更新 : 2016-11-07 

    EF 1-1 的条件是 primaryKey 必须是 foreignKey, 也就是说 2 个 table 的 Id 必须是一样的值, 如果无法做到这一点, 则 1-1 无法成立.

    当 1-1 遇上继承 TPH, 以上的条件就无法实现了, 

    这种情况下,我们只能无奈的使用 1-n 来替代, 然后在 foreignkey 的 table 上加上 unique 限制来模拟 1-1 的效果. 用起来很别扭, 但是目前没有好的方式去支持..无奈.

    1-n 设置

        //1-n 
        /*
            基本上如果没有必要就不要写required了,这样比较方便在update单个table的时候.(insert的时候自己要控制好!)
        */
        [Table("prod")]
        public class Prod
        {
            [Key]
            public int prodId { get; set; }
            public string code { get; set; }
            [InverseProperty("prod")] //因为有超过1个,所以我们要告诉entity,这对应哪一个
            public virtual ICollection<Color> colors { get; set; } //有多个colors,用ICollection | List 也可以
            [InverseProperty("prodx")]  
            public virtual ICollection<Color> color2s { get; set; } 
        }
    
        [Table("color")]
        public class Color
        {
            [Key]
            public int colorId { get; set; }
            public string name { get; set; }
    
            [ForeignKey("prod")] //指定一个FK, "prod" 是attr属性名,不是sql的哦
            public int prodId { get; set; }
       [ForeignKey("prodId")] //虽然写这里也是可以表达foreignKey 关系,但是最好不要这样!
    public virtual Prod prod { get; set; } //有一个prod [ForeignKey("prodx")] public int prodxId { get; set; } public virtual Prod prodx { get; set; } }
    InverseProperty (如果有做,lastModifier,handler就会有了),2个表有超过1个 1-n 关系,就要表明清楚对应的是哪一个。
    1-n 的 foreignKey 不可以是 0, 如果真的没有也只能放 Null, 而且sql 要是nullable , foreignKey 类型是 int?.
    nullable 虽然不会影响sql对foreignKey关系的验证或者级联,但是对索引搜索不好,所以还个简单的方法就是主表default create 1 row for 这种没有的情况,那么foreignKey 就可以连接到这row id 了。

     n-n 设置

    n-n 我不鼓励用 DataAnnotation, 除非用 default的tableName,比如 category , prod  = prodcategories , columns = Prod_prodId , Category_categoryId (基本上debug几次就可以知道它的自动命名了)

    如果是要自己取名字的话,比如 category_and_prod,那就麻烦多多了...

    参考 : https://social.msdn.microsoft.com/Forums/en-US/9d7a4803-53c6-44be-823d-dce6e85bb497/ef-41-customize-codefirst-manytomany-table-using-attributes

        /*
           2表的连接表 
        */
        [Table("prod_mm_category")]
        public class ProdAndCategory
        {
           
            [Key]
            public Int32 ProdAndCategoryId { get; set; }
            [Key]
            [Column(Order = 1)]
            [ForeignKey("category")]
            public int categoryId { get; set; }
            [Key]
            [Column(Order = 2)]
            [ForeignKey("prod")]
            public int prodId { get; set; }
            public Category category { get; set; }
            public Prod prod { get; set; }
        }
        [Table("category")]
        public class Category
        {
            [Key]
            public Int32 categoryId { get; set; }
            public string name { get; set; }
            /*
                注意这里是 ProdAndCategory 哦
            */
            public virtual ICollection<ProdAndCategory> prods { get; set; } 
        }
        [Table("prod")]
        public class Prod
        {
            [Key]
            public Int32 prodId { get; set; }
            public string code { get; set; }
            public virtual ICollection<ProdAndCategory> categorys { get; set; }
        }
    View Code

    insert 也超麻烦..

    db.categorys.Add(new Category
    {
        name = "Man",
        prods = new List<ProdAndCategory> 
        {
            /*
                这里很麻烦吧... 
            */
                new ProdAndCategory 
                {
                    prod = new Prod 
                    {
                    code = "MK100",
                    }
                },
                new ProdAndCategory 
                {
                    prod = new Prod 
                    {
                    code = "MK200",
                    }
                },
        }
    });
    View Code

    所以可以考虑用 Fluent API 替代

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        /*
            cateogry "HasMany" prod , prod "WithMany" category , mapping logic            
        */
        modelBuilder.Entity<Category>().HasMany<Prod>(c => c.prods).WithMany(p => p.categorys).Map(m =>
        {
            m.MapLeftKey("Category_categoryId"); //第3 table 的连接 columnName 可以自己顺便取
            m.MapRightKey("prodId"); //第3 table 的连接 columnName 
            m.ToTable("prodcategories"); //第3 tableName
        });
        base.OnModelCreating(modelBuilder);         
    }

    用 Fluent API 或是自动命名 insert 也简单了 

    db.categorys.Add(new Category
    {
        name = "Man",
        prods = new List<Prod> 
        {
            new Prod 
            {
                code = "MK100",
            },
            new Prod 
            {
                code = "MK200",
            } 
        }
    });
    db.SaveChanges();
    View Code

    更新 : 2015-10-08 

    有一种关系叫 双向 1对1 

    参考 : 

    http://stackoverflow.com/questions/6276299/creating-bidirectional-one-one-relationship-in-entity-framework-4-1-code-first

    http://weblogs.asp.net/manavi/associations-in-ef-4-1-code-first-part-5-one-to-one-foreign-key-associations

    个人不推荐使用,最明显的缺点是如果要删除关系,必须同时修改2个表的外键.

    可以考虑使用多对多来做替代,虽然这样也不是很理想啦 ( 有best way的话请告诉我哦! )

  • 相关阅读:
    ideal配置使用Git
    git帮助和小结
    Git的配置
    Git安装
    navicat下载安装和激活一分钟完成
    eclipse安装svn插件
    [数据结构
    [数据结构
    Qt对话框之二:模态、非模态、半模态对话框
    Qt 窗口操作函数(置顶、全屏,最大化最小化按钮设置等)
  • 原文地址:https://www.cnblogs.com/keatkeat/p/4072338.html
Copyright © 2011-2022 走看看