How to map a view without an identity column in NHibernate?

2.7k Views Asked by At

I have a view that I am going to only read from (no writes). This view does not have any unique key (not event composite).

So how can I map this view in NHibernate without touching the view? I do not want to add a new column to the view to generate a unique identity for me. Is there a way to map this view and generate the identity column on the NHibernate side?

I can generate a GUID in my entity class like:

public class MyViewClass
{
    private Guid _id = new Guid();
    public virtual Guid Id { get { return _id; } set { _id = value; } }
}

But how can I make the mapping work? The following code does not work:

public class MyViewClass: ClassMapping<MyViewClass>
{
    public MyViewClass()
    {
        Mutable(false);
        Id(x => x.Id, m => m.Generator(Generators.Guid));
    }

} 

It expects to have the Id column in view and throws:

System.Data.SqlClient.SqlException: Invalid column name 'Id'.

BTW, I am using NHibernate 3.2 and mapping by code.

2

There are 2 best solutions below

0
On

From what I understand, NHibernate needs an Id column to be able to map a view to the entity. So to fulfill this requirement, there are 2 ways:

  1. Add an Id column. In my case, since my view is a summary of a table with an Id column, I just added the Id column also in the view definition.
  2. Add a composite Id from multiple columns in the mapping class.

In the mapping class I also needed to add SchemaAction(.), otherwise NHibernate will complain on runtime that it cannot map the entity to a table/view.

The mapping class would look like this (Either choose option 1 or 2):

public class EntityMap : ClassMapping<Entity> {

  public EntityMap() {
    SchemaAction(NHibernate.Mapping.ByCode.SchemaAction.None);
    Table("NameOfTheView");
    Mutable(false);

    // Option 1
    Id(e => e.Id, map => map.Column("Id"));

    // Option 2
    // NOTE: With ComposedId you need to override Equals() and GetHashCode() in the entity class
    ComposedId(map => {
      map.Property(e => e.Column1);
      map.Property(e => e.Column2);
    });

    // Additional mapping code
  }
}

I also prefer mapping the view to an entity because then I can use QueryOver or Query (LINQ) API to eliminate the use of magic strings (table/column names) in a normal SQL query.

3
On

Update: to use it in LINQ map all columns as CompositeId and Mutable(false) then override Equals and GetHashCode with default implementation.

public class MyViewClass
{
    public override bool Equals(object obj)
    {
        return base.Equals(obj);
    }

    public override int GetHashCode()
    {
        return base.GetHashCode();
    }
}

original answer:

i wouldnt map it at all if you dont want to insert/update it

public class MyViewClass
{
    public virtual string Prop1 { get; set; }
    public virtual int Prop2 { get; set; }
}

var viewObjects = session.CreateSQLQuery("SELECT col1 as Prop1, col2 as Prop2 FROM MyView")
    .SetResultTransformer(Transformers.AliasToBean<MyViewClass>())
    .List<MyViewClass>();