Fluent NHibernate 官方示例(增加中文注释整理,稍有修改)

祁渊
2023-12-01

为什么用 Fluent NHibernate ?

Fluent NHibernate提供了一个方法让你不再需要去写NHibernate的标准映射文件(.hbm.xml),而是可以把你的映射文件都使用C#来写。这样做,方便了我们的代码重构,提供了代码的易读性,并精简了项目代码。

开发环境 VS 2019。

1.Examples.FirstProject

让我们开始第一个 Fluent NHibernate 程序。

实体的类如下:

Employee:

    public class Employee
    {
        public virtual int Id { get; protected set; } 
        public virtual string FirstName { get; set; }
        public virtual string LastName { get; set; }
        public virtual Store Store { get; set; }
    }

类中的属性需要定义为 virtual , Id 是自动递增的。

Location:

   public class Location
    {
        public virtual int Aisle { get; set; }
        public virtual int Shelf { get; set; }
    }

Product:

    public class Product
    {
        public virtual int Id { get; protected set; }
        public virtual string Name { get; set; }
        public virtual double Price { get; set; }
        public virtual Location Location { get; set; }
        public virtual IList<Store> StoresStockedIn { get; set; }

        public Product()
        {
            StoresStockedIn = new List<Store>();
        }
    }

Store:

    public class Store
    {
        public virtual int Id { get; protected set; }
        public virtual string Name { get; set; }
        public virtual IList<Product> Products { get; set; }
        public virtual IList<Employee> Staff { get; set; }

        public Store()
        {
            Products = new List<Product>();
            Staff = new List<Employee>();
        }

        public virtual void AddProduct(Product product)
        {
            product.StoresStockedIn.Add(this); // 多对多
            Products.Add(product);
        }

        public virtual void AddEmployee(Employee employee)
        {
            employee.Store = this; // 一对多 
            Staff.Add(employee);
        }
    }

每个实体有一个对应的Mapping文件。

Employee的mapping如下:

    public class EmployeeMap : ClassMap<Employee>
    {
        public EmployeeMap()
        {
            Id(x => x.Id);
            Map(x => x.FirstName);
            Map(x => x.LastName);
            References(x => x.Store);
        }
    }

很明显这里的Map方法相当于XML配置文件的Property, 而Reference相当于Many-To-One。

Location的Mapping如下:

public class LocationMap : ComponentMap<Location>
{
    public LocationMap()
    {
        Map(x => x.Aisle);
        Map(x => x.Shelf);
    }
} 

Product的Mapping如下:

    public class ProductMap : ClassMap<Product>
    {
        public ProductMap()
        {
            Id(x => x.Id);
            Map(x => x.Name);
            Map(x => x.Price);
            HasManyToMany(x => x.StoresStockedIn)
                .Cascade.All()
                .Inverse()
                .Table("StoreProduct");
            Component(x => x.Location);
        }
    }

这里的HasManyToMany相当于NHibernate中的Many-To-Many。在映射的两端同时添加HasManyToMany的关系这样就形成了双向的关联关系。这里用Inverse(),下面不要用。关联关系的两方都要指定相同的 Table()。

Store 的 Mapping 如下:

    public class StoreMap : ClassMap<Store>
    {
        public StoreMap()
        {
            Id(x => x.Id);
            Map(x => x.Name);
            HasManyToMany(x => x.Products)
                .Cascade.All()
                .Table("StoreProduct");
            HasMany(x => x.Staff)
                .Cascade.All()
                .Inverse();
        }
    }

这里的HasMany相当于NHibernate中Many-To-One。

下一步是创建数据库和SessionFactory:

SessionFacotry:

    private static ISessionFactory CreateSessionFactory()
    {
        var fluentlyConfigure = Fluently.Configure()
            .Database(SQLiteConfiguration.Standard
            .UsingFile(DbFile))
            .Mappings(m => {
                m.FluentMappings.AddFromAssemblyOf<Program>();
            });
        fluentlyConfigure = fluentlyConfigure.ExposeConfiguration(BuildSchema);
        return fluentlyConfigure.BuildSessionFactory();
    }

运行程序,数据库中表会自动创建,且数据添加成功。

最后增加一个 First 布尔标识,检查是否存在现有的数据文件, 如果存在就使用现有的,不重新创建及添加数据。

全部工作完成。

2.Examples.FirstAutomappedProject

这个例子是上个例子的 AutoMapped 版本。主要不同点在于,不用自己创建 Mapping,使用 AutoMapping 自动创建 Examples.FirstAutomappedProject.Entities 名字空间下的实例的Mapping , 其余部分与 上个例子类似。

重要的区别如下:

class ExampleAutomappingConfiguration : DefaultAutomappingConfiguration
{
    public override bool ShouldMap(Type type)
    {
        return type.Namespace.EndsWith(".Entities");
    }

    public override bool IsComponent(Type type)
    {
        return type == typeof(Location);  // Location 对应 ComponentMap ,其他对应 ClassMap
    }
}

注意思考 Location 和 其他实体有什么不同的地方。

class CascadeConvention : IReferenceConvention, IHasManyConvention, IHasManyToManyConvention
{
    public void Apply(IManyToOneInstance instance)
    {
        // FluentNHibernate在映射时有很多种映射方法。
        // Cascade它是指该对象在进行操作时关联到的子对象的操作类型,指定All说明所有的操作都会关联到子表
        instance.Cascade.All(); 
    }
    public void Apply(IOneToManyCollectionInstance instance)
    {
        instance.Cascade.All();
    }
    public void Apply(IManyToManyCollectionInstance instance)
    {
        instance.Cascade.All();
    }
}

多对一,一对多,多对多 均在这个类中级联。

以上完整的例子 在 这里

全部工作完成。

参考资料 :

基本映射详解: https://blog.csdn.net/zhang_xinxiu/article/details/42131907

AutoMapping详解: https://blog.csdn.net/zhang_xinxiu/article/details/42248565

 类似资料: