• [Study Note] NHibernate in Action 20100522


    Part 2 NHibernate deep dive

    3 Writing and mapping classes

    business objects / entities

    domain model

    mapping metadata

    3.1 The CaveatEmptor application

    3.1.1 Analyzing the business domain

    A software development effor begins with analysis of the problem domain.

    Developers of object-oriented software analyze the business model and create an object model, still at the conceptual level (no C# code).

    domain model – an object-oriented model of entities from the problem domain. It’s an abstract view of the real word.

    3.1.2 The CaveatEmptor domain model

    The entities in a domain model should encapsulate state and behavior.

    rich object model with complex associations, interactions, and inheritance relationships.

    Patterns of Enterprise Application Architecture [Fowler 2003]

    Domain-Driven Design [Evans 2004]

    3.2 Implementing the domain model

    automated / transparent

    3.2.1 Addressing leakage of concerns

    The domain-model implementation is such an important piece of code that it shouldn’t depend on other .NET APIs.

    domain model should be “concerned” only with modeling the business domain.

    cross-cutting concerns

    transparent persistence

    3.2.2 Transparent and automated persistence

    NHibernate can automatically persist your changes in a way that is transparent to your domain model.

    • NHibernate doesn’t require that any special base classes or interfaces be inherited or implemented by persistent class. Nor are any special classes used to implement properties or associations.
    • Persistent class may be reused outside the context of persistence.
    • In a system with transparent persistence, objects aren’t aware of the underlying data store; they need not even be aware that they’re being persisted or retrieved. Persistence concerns are externalized to a generic persistence manager interface -  in the case of NHibernate, the ISession and IQuery interface.

    Testability is a basic requirement for applications with rich domain models.

    3.2.3 Writing POCOs

    POCO, Plain Old CLR Object

    A POCO declares business methods, which define behavior, and properties, which represent state.

    NHibernate doesn't require persistent classes to be serializable.

    NHibernate requires a default parameterless contructor for every persistent class.

    Note that .NET automatically adds a public paramenterless constructor to classes if you haven't writen one in the code.

    The properties of the POCO implement the attributes of your business entities.

    NHibernate doesn’t require that properties be declared public; it can easily use private ones too.

    3.2.4 Implementing POCO associations

    scaffolding code

    single-valued end / many-valued end

    NHibernate requires interfaces for collection-typed attributes. … At runtime, NHibernate wraps the collection instance with an instance of one of NHibernate’s own classes.

    grouping of operations

    many-to-many association

    3.2.5 Adding logic to properties

    custom type

    dirty checking

    NHibernate automatically detects objectstate changes in order to synchronize the updated state with the database.

    NHibernate compares the objects by values – not by object identity – to determine whether the property’s persistent state needs to be updated.

    Collections are compared by identity!

    Note that collections shouldn’t have a setter at all.

    3.3 Defining the mapping metadata

    ORM tools require a metadata format for the application to specify the mapping between classes and tables, properties and columns, associations and foreign keys, .NET types and SQL types. This information is called the object/relational mapping metadata. It defines the transformation between the different data type systems and relationship representations.

    3.3.1 Mapping using XML

    backlash against the overuse of XML

    1. Many existing metadata formats weren’t designed to be readable and easy to edit by hand. … lack of sensible defaults for attribute and element values
    2. Metadata-based solutions were often used inappropriately.
    3. Good XML editors, especially in IDEs, aren’t as common as good .NET coding environments.

    object identity

    NHibernate will use .NET reflection to discover the type of this property and deduce how to map it to the SQL column, assuming they have compatible types.

    mapping data type

    3.3.2 Attribute-oriented programming

    3.4 Basic property and class mappings

    3.4.1 Property mapping overview

    A typical NHibernate property mapping defines a property name, a database column name, and the name of an NHibernate type. It maps a .NET property to a table column.

    NHibernate uses reflection to determine the .NET type of the property.

    3.4.2 Using derived properties

    The value of a derived property is calculated at runtime by evaluating an expression. … define the expression using the formula attribute.

    3.4.3 Property access strategies

    nosetter.* | field.camelcase-underscore

    <hibernate-mapping default-access=”…” >

    HbmSerializer.HbmDefaultAccess

    customized property access strategy

    NHibernate.Property.IPropertyAccessor

    [Property(AccessType=typeof(MyPrpertyAccessor))]

    3.4.4 Taking advantage of the reflection optimizer

    disable reflection optimizer

    <property name=”hibernate.use_reflection_optimizer”>false</property>

    Environment.UseReflectionOptimizer = false;

    select the CodeDom provider

    <property name=”hibernate.bytecode.provider”>codedom</property>

    null | lcg

    Environment.BytecodeProvider

    Environment.BuildBytecodeProvider()

    NHibernate.Bytecode.IBytecodeProvider

    3.4.5 Controlling insertion and updates

    <property name=”Name” column=”Name” type=”String” insert=”false” update=”false” />

    immutable classes is that you’ve decided should never be updated after they’ve been created.

    dynamic-insert / dynamic-update

    Enabling either of these settings causes NHibernate to generate SQL at runtime instead of using the SQL cached at startup time. The performance and memory cost of doing this is unually small.

    3.4.6 Using quoted SQL identifiers

    quote a table or column name with backticks (`) in the mapping document, NHibernate always quotes this identifier in the generated SQL.

    3.4.7 Naming convertions

    INamingStrategy

    Configuration cfg = new Configuration();

    cfg.NamingStrategy = new CENamingStrategy();

    ISessionFactory sessionFactory = cfg.configure().BuildSessionFactory();

    3.4.8 SQL schema

    … specify a default schema using hibernate.default_schema configuration option, doing so offers some small performance benefits.

    3.4.9 Declaring class name

    Configuration.SetDefaultNamespace()

    Configuration.SetDefaultAssembly()

    3.4.10 Manipulating metadata at runtime

    NHibernate.Mapping – Column, SimpleValue, and Property

    NHibernate.Type – StringType

    … adding a property to an existing persistent class mapping is easy …

    Once an ISessionFactory is created, its mappings are immutable.

    ISessionFactory – GetClassMetadata(), GetCollectionMetadata()

    3.5 Understanding object identify

    3.5.1 Identity versus equality

    Object identity, object.ReferenceEquals(), is a notion defined by the CLR environment. Two object references are identical if they point to the same memory location.

    Object equality is a notion defined by classes that implement the Equals() method ( or the operator == ), sometimes also referred to as equivalence.

    • Object identity – Objects are identical if they occupy the same memory location. This can be checked by using object.ReferenceEquals().
    • Object equality – Objects are equal if they have the same value, as defined by the Equals(object o) method. Classes that don’t explicitly override this method inherit the implementation defined by System.Object, which compares object identity.
    • Database identity – Objects stored in a relational database are identical if they represent the same row or, equivalenty, share the same table and primary key value.
    3.5.2 Database identity with NHibernate
    • The value of the identifier property of a persistent instance
    • The value returned by ISession.GetIdentifier(object o)
    3.5.3 Choosing primary keys

    primary key

    A candidate key is a column or set of columns that uniquely identifies a specific row of the table.

    1. The value or values are never null.
    2. Each row has a unique value or values.
    3. The value or values of a particular row never change.

    A natural key is a key with business meaning: an attribute or combination of attributes that is unique by virtue of its business semantics.

    if a candidate key attribute has meaning outside the database context, it’s a natural key, whether or not it’s automatically generated.

    Experience has shown that natural keys almost alway cause problems in the long run.

    A good primary key must be unique, constant, and required (never null or unknown).

    Surrogate keys ( also called synthetic identifiers ) have no business meaning -  they’re unique values generated by the database or application.

    IIdentifierCenerator

    composite keys , natural keys composed of multiple table columns.

    其实如果有机会的话,在Oracle的数据环境下,我倾向于使用 GUID 来作为主键的生成方式,这样似乎可以减少访问数据库的次数。手头的项目暂时只能把主键都切换到 sequence 生成方式(我以为,这种生成方式在插入数据的时候需要先查询一次 sequence,可能会稍微损失一点性能)。

    3.6 Fine-grained object model

    A major objective of the NHibernate project is support for fine-grained object  models, which we isolated as the most important requirement for a rich domain model.

    … fine-grained means “more classes than tables” …

    3.6.1 Entity and value types

    In .NET, all classes are of equal standing: all objects have their own identity and lifecycle, and all class instances are passed by reference. Only primitive types are passed by value.

    • An object of entity type has its own database identity (primary-key value). An object reference to an entity is persisted as a reference in the database ( a foreign-key value). An entity has its own lifecycle; it may exist independently of any other entity.
    • An object of value type has no database identity; it belongs to an entity, and its persistent state is embedded in the table row of the owning entity. Value types don’t have identifier or identifier properties. The lifespan of a value-type instance is bounded by the lifespan of the owning entity.
    3.6.2 Using components

    … in the context of ORM, a composed class is often a candidate value type.

    .NET has no concept of composition -  a class or attribute can’t be marked as a component or composition.

    [RawXml] Attribute

    <parent> element

    • Shared reference aren’t possible
    • There is no elegant way to represent a null reference to an Address.

    3.7 Introducing associations

    3.7.1 Unidirectional associations
    3.7.2 Mutiplicity

    from Bid to  Item is a many-to-one association, from Item to Bid is a one-to-many association.

    from Employee to Department is a many-to-one association, from Department to Employee  is one-to-many association.

    我觉得这个关系有点像主表和字典表之间的对应。

    3.7.3 The Simplest possible association

    <many-to-one name="Item" column="ITEM_ID" class="Item" not-null="true" />

    <many-to-one … not-found=”ignore|exception” />

    3.7.4 Making the association bidiretional

    The inverse attribute tells NHIbernate that the collection is a mirror image of the many-to-one association on the other side.

    联系实际,如果在单位类映射文件里面,在雇员集合上设定:inverse=true,如此一来,雇员的单位属性修改的时候会触发update,而仅仅对单位的雇员们集合修改的时候不触发。

    cascading saves

    cascading deletes

    3.7.5 A parent/child relationship

    parent/child relationship the parent entity is responsible for the lifecycle of its associated child entities.

    cascade=”all-delete-orphan”

    • Any newly instantiated Bid becomes persistent if the Bid is referenced by a persistent Item. ( as is also the case with cascade=”save-update”). Any persistent Bid should be deleted if it’s referenced by an Item when the item is deleted.
    • Any persistent Bid should be deleted if it’s removed from the bids collection of a persistent Item. (NHibernate will assume that it was only referenced by this item and consider it an orphan.)

    Keeping your association mappings simple and using NHibernate queries for more complex tasks.

    3.8 Mapping class inheritance

    catalogued by Scott Ambler [Ambler 2002]

    • Table per concrete class – Discard polymorphism and inheritance relationships from the relation model.
    • Table per class hierarchy – Enable polymorphism by denormalizing the relational model and using a type a type-discriminator column to hold type information.
    • Table per subclass – Represent “is a” (inheritance) relationships as “has a”(foreign key) relationships.
    3.8.1 Table per concrete class

    polymorphic queries queries that return objects of all classes that match the interface of the queries class.

    This approach (only) for the top level of your class hierarchy, where polymorphism isn’t usually required.

    3.8.2 Table per class hierarchy

    type discriminator

    This mapping strategy is a winner in terms of both performance and simplicity.

    major problem: NOT NULL constraints

    3.8.3 Table per subclass

    represent inheritance relationships as relational foreign-key associaations. Every subclass that declares persistent properties – including abstract classes and even interface – has its own table.

    <joined-subclass name=”CreditCard” table=”CREDIT_CARD”>

        <key column=”CREDIT_CARD_ID”>

        <property name=”Type” column=”Type” />

    </joined-subclass>

    Even though this mapping strategy is deceptively simply, … performance may be unacceptable for complex class hierarchies.

    3.8.4 Choosing a strategy

    NHibernate won’t try to instantiate an abstract class, even if you query or load it.

    • If you don’t require polymorphic associations or queries, lean toward the table-per-class strategy. If you require polymorphic associations (an association to a base class, hence to all classes in the hierarchy with dynamic resolution of the concrete class at runtiime) or queries, and subclasses declare relatively few properties  (particularly if the main difference between subclass is in their behavior), lean toward the table-per-class-hierarchy model.
    • If you require polymorhpic associations or queries, and subclass declare many properties (subclasses differ mainly by the data they hold), lean toward the table-per-subclass approach.

    By default, choose table-per-class-hierarchy for simple problems.

    Note that you may also use <subclass> and <joined-subclass> mapping elements in a separate mapping file (as a top-level element, instead of <class>).

    3.9 Summary

  • 相关阅读:
    python中特殊参数self的作用
    python中类的初始化案例
    python中类的调用
    Python--网络编程-----struct模块的字节数限制
    Python--网络编程-----解决粘包问题-简单版
    Python--网络编程-----粘包的底层原理分析
    Python--网络编程-----粘包现象
    Python--网络编程-----socket编程示例--模拟ssh远程执行命令
    pycharm下 os.system执行命令返回有中文乱码
    Python--网络编程-----socket编程示例--打电话--加上链接循环
  • 原文地址:https://www.cnblogs.com/zhaorui/p/1742423.html
Copyright © 2020-2023  润新知