What are some reasons NHibernate will not execute SQL? - c#

I am using Fluent NHibernate to map entities and am having a problem getting a repository to give a resultset. In the console, the SQL does not show but other repositories do. I have a feeling that it is because of the Mappings but can't tell why. The table name includes an underscore which is one of the only differences between this repo and others. My question is what could cause the sql not to be executed?
Here is my setup.
Entity:
public class Org
{
public virtual int ID { get; set; }
public virtual string IndividualName { get; set; }
public virtual string GroupName { get; set; }
public virtual string AddressLine1 { get; set; }
public virtual string AddressLine2 { get; set; }
}
Mapping:
public class OrgMap : ClassMap<Org>
{
public OrgMap()
{
Table(#"Org_Updates"); // Also tried Table("Org_Updates");
Map(x => x.ID);
Map(x => x.IndividualName);
Map(x => x.GroupName);
Map(x => x.AddressLine1, "PhysicalLocationAddress");
Map(x => x.AddressLine2, "PLAddr2");
Repository:
public class OrgRepository : RepositoryBase<Org>, IOrgRepository
{
public IList<Org>GetTop50()
{
var query = All().AsList();
return query;
}
}
RepositoryBase:
public class OrgRepositoryBase<T> : RepositoryBase<T> where T : class
{
public OrgRepositoryBase()
{
var registry = ServiceLocator.Current.GetInstance<EventListenerRegistry>();
registry.RegisterListenerForType<T>(GetType(), EventType.Save);
registry.RegisterListenerForType<T>(GetType(), EventType.Delete);
}
protected override ISession GetSession()
{
return UnitOfWork.Current.GetSessionFromContext<ISession>(typeof (OrgModel));
}
protected override Type ModelType
{
get { return typeof (OrgModel); }
}
}
}
As I said before, the other repositories that use other entites/mapping work. I can use this repository, exchanging the entity/mapping that it implements and it will work. I'm pretty sure it's because of hte mapping but can't tell which part. I have checked the table name and the column names.
Thanks for the help

I am making an assumption here that your table does have a primary key. If so, should you not map that primary key
public class OrgMap : ClassMap<Org>
{
public OrgMap()
{
Table(#"Org_Updates");
Id(x => x.ID);
Map(x => x.IndividualName);
Map(x => x.GroupName);
Map(x => x.AddressLine1, "PhysicalLocationAddress");
Map(x => x.AddressLine2, "PLAddr2");

Related

TPC in Entity Framework v6

I'm trying to do a pretty simple thing in Entity Framework.
I have a product that has zero or more parameters and these parameters will be mapped to their own tables. However, I'm unable to get this to work. I've been trying to get the mappings right and then use the migrations to see what the database is supposed to look like. I know that this is very simple in NHibernate, but I'm forced against my will to use Entity Framework v6.
Background
These are my entities:
namespace Entities
{
public class EntityState
{
public int Id { get; set; }
}
public class ProductState : EntityState
{
public virtual ICollection<ProductParameterState> Parameters { get; set; }
}
public abstract class ProductParameterState : EntityState
{
}
public class ColorParameterState : ProductParameterState
{
public virtual string Color { get; set; }
}
public class SizeParameterState : ProductParameterState
{
public virtual int Size { get; set; }
}
}
I would like to store this in the following schema:
How to do this?
My attempts
Table-per-class
I tried mapping using TPC:
namespace Mappings
{
public class ProductMap : EntityTypeConfiguration<ProductState>
{
public ProductMap()
{
HasKey(x => x.Id);
Property(x => x.Name);
HasMany(x => x.Parameters);
}
}
public class ColorParameterMap : EntityTypeConfiguration<ColorParameterState>
{
public ColorParameterMap()
{
HasKey(x => x.Id);
Property(x => x.Color);
Map(x =>
{
x.ToTable("ColorParameters");
x.MapInheritedProperties();
});
}
}
public class SizeParameterMap : EntityTypeConfiguration<SizeParameterState>
{
public SizeParameterMap()
{
HasKey(x => x.Id);
Property(x => x.Size);
Map(x =>
{
x.ToTable("SizeParameters");
x.MapInheritedProperties();
});
}
}
}
But this gives the error The association 'ProductState_Parameters' between entity types 'ProductState' and 'ProductParameterState' is invalid. In a TPC hierarchy independent associations are only allowed on the most derived types..
Don't use an inheritence strategy
So I tried to remove the MapInheritedProperties, but then it wants to create an additional, and unwanted, table:
CreateTable(
"dbo.ProductParameterStates",
c => new
{
Id = c.Int(nullable: false, identity: true),
ProductState_Id = c.Int(),
})
.PrimaryKey(t => t.Id)
.ForeignKey("dbo.ProductStates", t => t.ProductState_Id)
.Index(t => t.ProductState_Id);
I don't want this. I am able to get rid of this one by removing the Parameters property in Product, but then I'm not able to use the Parameters of a Product.
Am I asking for too much or is it possible?
You can use TPC, but the relationship must be bidirectional with explicit FK defined (which I guess is the opposite of "independent association" mentioned in the error message).
Add inverse navigation property and FK property to your base entity:
public abstract class ProductParameterState : EntityState
{
public int ProductId { get; set; }
public ProductState Product { get; set; }
}
and use the same entity configurations as in your first attempt, except for the ProductMap where you either remove the following
HasMany(x => x.Parameters);
or change it to
HasMany(e => e.Parameters)
.WithRequired(e => e.Product)
.HasForeignKey(e => e.ProductId);

NHibernate How do i put data in many to many mapping

These are my two classes. I did the mapping and the configuration.
Please instruct me how do I put data into this.
class Actor
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual IList <Movies> Movie{ get; set; }
}
class Movies
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual IList <Actor> Actors{ get; set; }
}
I'm not sure what exactly you are asking here, but I'll try to answer what I think you are asking.
In order to map a many-to-many relationship to the database with Fluent NHibernate for the classes in your question would be as simple as
public class ActorMap : ClassMap<Actor>
{
public ActorMap()
{
Id(x => x.Id);
Map(x => x.Name);
HasManyToMany(x => x.Movies)
.Table("Actors_Movies")
.ParentKeyColumn("ActorId")
.ChildKeyColumn("MovieId")
.LazyLoad()
.Cascade.AllDeleteOrphan();
}
}
public class MovieMap : ClassMap<Movie>
{
public MovieMap()
{
Id(x => x.Id);
Map(x => x.Name);
HasManyToMany(x => x.Actors)
.Table("Actors_Movies")
.ParentKeyColumn("ActorId")
.ChildKeyColumn("MovieId")
.Inverse();
}
}
The junction table in the database is transparent to the relationship in code; consider this an artifact of the impedance mismatch of mapping object oriented code to a relational database.
Now, if you needed to store additional data against the junction table, you would need to expose a type in code to represent the junction table, and add properties to this type for the data you wish to store
public class MovieActorAssociation
{
public MovieActorAssociation(Actor actor, Movie movie)
{
Actor = actor;
Movie = movie;
}
protected MovieActorAssociation()
{
}
public virtual Actor Actor { get; protected set; }
public virtual int Id { get; protected set; }
public virtual Movie Movie { get; protected set; }
public virtual string SomeOtherProperty { get; set; }
public static bool operator ==(MovieActorAssociation left, MovieActorAssociation right)
{
return Equals(left, right);
}
public static bool operator !=(MovieActorAssociation left, MovieActorAssociation right)
{
return !Equals(left, right);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
if (ReferenceEquals(this, obj))
{
return true;
}
if (obj.GetType() != GetType())
{
return false;
}
return Equals((MovieActorAssociation)obj);
}
public override int GetHashCode()
{
return Id;
}
protected bool Equals(MovieActorAssociation other)
{
return Id == other.Id;
}
}
Now, to map the relationship
public class ActorMap : ClassMap<Actor>
{
public ActorMap()
{
Id(x => x.Id).GeneratedBy.Identity();
Map(x => x.Name);
HasMany(x => x.MovieAssociations)
.Cascade.AllDeleteOrphan()
.Inverse()
.KeyColumn("ActorId")
.Not.KeyNullable();
}
}
public class MovieActorAssociationMap : ClassMap<MovieActorAssociation>
{
public MovieActorAssociationMap()
{
Id(x => x.Id).GeneratedBy.Identity();
Map(x => x.SomeOtherProperty);
References(x => x.Movie)
.Not.Nullable()
.Cascade.SaveUpdate()
.Column("MovieId")
.UniqueKey("Movie_Actor");
References(x => x.Actor)
.Not.Nullable()
.Cascade.SaveUpdate()
.Column("ActorId")
.UniqueKey("Movie_Actor");
}
}
public class MovieMap : ClassMap<Movie>
{
public MovieMap()
{
Id(x => x.Id).GeneratedBy.Identity();
Map(x => x.Name);
HasMany(x => x.ActorAssociations)
.Cascade.AllDeleteOrphan()
.Inverse()
.KeyColumn("MovieId")
.Not.KeyNullable();
}
}
And to use
var actor = new Actor { Name = "Actor Name" };
var movie = new Movie { Name = "Movie Name" };
var association = new MovieActorAssociation(actor, movie);
actor.MovieAssociations.Add(association);
movie.ActorAssociations.Add(association);
// some way of getting a Session
var session = SessionFactory.GetCurrentSession();
using (var transaction = session.BeginTransaction())
{
session.Save(actor);
transaction.Commit();
}
You may want to consider exposing methods for adding and removing MovieActorAssociation types to ensure association correctness i.e. that an association added to the property collection on an Actor references the Actor instance that owns the collection and not another actor instance. You would want similar logic to this for Movie types too.

Fluent NHibernate: One to One Mapping - reverse from primary column to a foreign key

I have a "Group" class and a "GroupSummaryLevel" class, codes are given below. There is a one-to-one relation between these entities in DB. I need the "GroupSummaryLevel" as a property in Groups class. It is supposed to be a very simple join like
(SELECT g.Id FROM GroupSummaryLevel g WHERE g.AcctGroup = GroupID)
Unfortunately, I wasn't able to figure this out how to do with NHibernate. The many answers I saw here is no help to me. I would appreaciate any inputs from the more experienced NHibernate users out there. Thanks in advance.
public class Group : DomainEntity
{
public virtual string GroupId { get; set; }
public virtual string GroupName { get; set; }
public virtual GroupSummaryLevel GroupSummaryLevel { get; set; }
}
public class GroupSummaryLevel : DomainEntity
{
public virtual int Id { get; set; }
public virtual string AcctGroup { get; set; }
public virtual GroupSummaryLevel Parent { get; set; }
public virtual IList<GroupSummaryLevel> Children { get; set; }
public GroupSummaryLevel()
{
Children = new List<GroupSummaryLevel>();
}
}
The mapping I have done did not work so far. My mapping codes are as below:
public GroupMap()
{
Table("Groups");
LazyLoad();
Id(x => x.GroupId).GeneratedBy.Assigned().Column("GroupID").CustomType<TrimmedString>();
Map(x => x.GroupName).Column("GroupName").CustomType<TrimmedString>().Not.Nullable();
HasOne(x => x.GroupSummaryLevel).Cascade.None().ForeignKey("AcctGroup");
}
public GroupSummaryLevelMap()
{
Table("GroupSummaryLevel");
LazyLoad();
Id(x => x.Id).GeneratedBy.Identity().Column("Id");
Map(x => x.AcctGroup).Column("AcctGroup").CustomType<TrimmedString>().Not.Nullable();
//References(x => x.Parent).Column("ParentId");
//HasMany(x => x.Children).Cascade.All().KeyColumn("ParentId");
}
Note: I also need to do a self-join for GroupSummaryLevel, and no success with that either. Any recommendations for that will also be appreciated :)
I would say, that your one-to-one is not driven by primary/foreign keys, but by property-ref. So the Group should map the summary by saying something like this:
...if you want to find related SummaryLevel, pass my <id> into column mapped as AcctGroup
public GroupMap()
{
...
HasOne(x => x.GroupSummaryLevel)
.Cascade.None()
//.ForeignKey("AcctGroup")
.PropertyRef(gsl => gsl.AcctGroup)
;
}
public GroupSummaryLevelMap()
{
...
//References(x => x.Parent).Column("ParentId");
//HasMany(x => x.Children).Cascade.All().KeyColumn("ParentId");
References(x => x.Parent, "AcctGroup");
}
NOTEs for completeness, as discussed in comments:
In this scenario, when the "child" has reference to parent - it really calls for one-to-many/.HasMany() mapping.
The down side is, that child is represented as a colleciton of children: IList<GroupSummaryLevel>. It is not as straighforward to use, but we can create some virtual property, returning the .FirstOrDefault(). The benefit we get - is lazy loading (not in place with one-to-one).

Inserting a parent entity with existing child in Fluent NHibernate

This is a general question, I'm sure it's quite common, however I haven't found anything on it (or I don't know what to search for I guess).
I'm having the following entities in my project:
public class User
{
public virtual int Id { get; set; }
public virtual string FirstName { get; set; }
public virtual string LastName { get; set; }
public virtual Unit Unit { get; set; }
}
public class Unit
{
public virtual int Id { get; set;}
public virtual string Name { get; set;}
}
This is how I've done the Fluent NHibernate mappings:
public class UserMap : ClassMap<User>
{
public UserMap()
{
Id(x => x.Id).GeneratedBy.Identity().Column("UserId");
Map(x => x.FirstName);
Map(x => x.LastName);
References(x => x.Unit).Column("UnitId");
}
}
public class UnitMap : ClassMap<Unit>
{
public UnitMap()
{
Table("Unit");
LazyLoad();
Id(x => x.Id).GeneratedBy.Identity().Column("UnitId");
Map(x => x.Name).Column("Name").Not.Nullable();
HasMany(x => x.Users).KeyColumn("UnitId");
}
}
Now here is my question. How do I create a new User if I only have the user's unit Id not a full unit object, and the unit already exists in the database (created previously) ?
Something like this:
public class TestClass
{
// Adding a user to a unit example
public void SavingAUser(int unitId)
{
var user = new User
{
FirstName = "TestFirstName",
LastName = "TestLastName",
Unit = new Unit() // <-- I have only the Id of the unit I don't actually have a unit object here I don't want to query the DB to get the full object, I already have the Id
};
var userRepository = new UserRepository();
userRepository.Save(user);
}
}
How would I go about something like this. I hope I'm making sense, if not please let me know I'll throw in more clarifications. I'm also pretty certain that this is a very common scenario
You can return a proxy to the unit without fetching it.
var user = new User
{
FirstName = "TestFirstName",
LastName = "TestLastName",
Unit = Session.Load<Unit>(unitId)
}
You'll need to expose the session object.

NHibernate - lazy loading: no session or session was closed

I'm confused by the following NHibernate behaviour:
Domain classes and mappings:
public class Category
{
public virtual int ID { get; set; }
public virtual string Name { get; set; }
private IList<Product> _products;
public virtual IList<Product> Products
{
get { return new List<Product>(_products).AsReadOnly(); }
}
public Category()
{
_products = new List<Product>();
}
}
public class Product
{
public virtual int ID { get; set; }
public virtual string Name { get; set; }
public virtual Category Category { get;set; }
}
public class ProductMap : ClassMap<Product>
{
public ProductMap()
{
Schema("dbo");
Table("tProducts");
Id(x => x.ID);
Map(x => x.Name);
References(x => x.Category).Column("CategoryID");
}
}
public class CategoryMap : ClassMap<Category>
{
public CategoryMap()
{
Schema("dbo");
Table("tCategories");
Id(x => x.ID);
Map(x => x.Name);
HasMany(x => x.Products)
.KeyColumn("CategoryID")
.Access.CamelCaseField(Prefix.Underscore)
.Inverse()
.Cascade.All();
}
}
Code causing trouble:
Category category;
using (var session = sessionFactory.OpenSession())
{
category = session.Get<Category>(1);
}
using (var session = sessionFactory.OpenSession())
{
var products = category.Products; // exception
}
Why do I get no session exception when I'm trying to get products? I've got a session here! How to avoid this exception (I prefer 2 sessions here, and I want to keep loading lazy)?
Thanks in advance!
Can you re-attach the object to your new session either:
ISession.Update(myDetachedInstance);
or, if the object has not been changed:
ISession.Lock(myDetachedInstance, NHibernate.LockMode.None);
For more info, see: http://intellect.dk/post/Detached-objects-in-nHibernate-and-Lazy-loading.aspx
I got this same error and it was due to the WPF UI holding on to references to objects from the old nhibernate session after I clicked the "refresh" button which called refresh on the data context which disassociated all cached objects in the session.
I needed to make sure "NotifyChange" was being fired to make the UI update (and that the UI was listening to it).

Categories