NHibernate Fluent CompositeId with CustomType mapping - c#

I have trouble creating the following mapping:
CompositeId(x => x.Id)
.KeyProperty(x => x.SiteId, "SiteID")
.KeyProperty(x => x.SomeId, "SomeId")
.KeyProperty(x => x.AnotherId, "AnotherId")
.KeyProperty(x => x.Dtg, "DTG");
Previously Dtg is not part of CompositeId so I can just put Dtg as:
Map(x => x.Dtg, "DTG").CustomType("DateTime2");
It requires DateTime2 as millisecond is required.
Now due to a change I will have to make Dtg as part of CompositeId.
So how do I put CustomType to Dtg? thanks for your help.

Solution found, adding .CustomType<TimestampType>() does not truncate milliseconds:
CompositeId(x => x.Id)
.KeyProperty(x => x.SiteId, "SiteID")
.KeyProperty(x => x.SomeId, "SomeId")
.KeyProperty(x => x.AnotherId, "AnotherId")
.KeyProperty(x => x.Dtg, "DTG").CustomType<TimestampType>();

Related

Mapping referenced table with C# automapper

Suppose I have a table Scopes which contains a foreign key to another table (subscopes) and I want to map it. All columns available in my Scopes table as well as some columns from my referenced table (subscopes) are required to be mapped to a DTO.
My questions are:
What should be the content of DTO?
How should I map using c# and Automapper?
this.CreateMap<tblSubScope, Sub2MainScopeDto>()
.ForMember(t => t.IdxSubScope, opt => opt.MapFrom(s => s.idxSubScope))
.ForMember(t => t.IdxMainScope, opt => opt.MapFrom(s => s.idxMainScope))
.ForMember(t => t.SubScopeDescription, opt => opt.MapFrom(s => s.strSubScope))
.ForMember(t => t.MainScopeDescription, opt => opt.MapFrom(s => s.tblMainScope.strMainScope))
.ReverseMap()
.ForMember(t => t.idxSubScope, opt => opt.MapFrom(s => s.IdxSubScope))
.ForMember(t => t.strSubScope, opt => opt.MapFrom(s => s.SubScopeDescription))
.ForMember(t => t.idxMainScope, opt => opt.MapFrom(s => s.IdxMainScope));
Problem Solved.

nHibernate: could not resolve property

i have spent hours trying to figure this out including going through all the previously asked questions on StackOverflow.
i am trying to query from the TrainingCourse by EvaluationHeadId, thats works fine, however, i try to get the TrainingRoute it returns "could not resolve property: TrainingRoute.TrainingRouteDefinition of: Model.Entities.TrainingCourse"
it saves perfect, my real problem is the query.
updated to:
using (var session = SessionProvider.Instance.OpenSession())
{
using (var transaction = session.BeginTransaction())
{
dto = session.QueryOver<TrainingCourse>()
.JoinQueryOver<EvaluationHead>(p => p.EvaluationHeads)
.JoinQueryOver<TrainingRoute>(p => p.TrainingRoute)
.Where(c => c.EvaluationHeadID == headId)
.SelectList(l => l
.Select(h => h.TrainingCourseDefn).WithAlias(() => d.TrainingCourseDefn)
.Select(h => h.IsAvailable).WithAlias(() => d.IsAvailable)
.Select(h => h.TrainingRoute.TrainingRouteDefinition).WithAlias(() => d.TrainingRouteDefinition))
.TransformUsing(Transformers.AliasToBean<TrainingCourseDTO>())
.List<TrainingCourseDTO>();
transaction.Commit();
}
}
Mappings:
public TrainingCourseMap()
{
Id(x => x.TrainingCourseID).GeneratedBy.Identity();
Map(x => x.TrainingCourseDefn);
Map(x => x.IsAvailable);
Map(x => x.TrainingCourseCreatedBy);
Map(x => x.TrainingCourseDtCreation);
Map(x => x.TrainingCourseDtModified);
Map(x => x.TrainingCourseModifiedBy);
References(x => x.TrainingRoute).Column("TrainingRouteID").Cascade.None();
HasManyToMany(x => x.EvaluationHeads).Table("EvaluationTraining").ParentKeyColumn("TrainingCourseID").ChildKeyColumn("EvaluationHeadID").Inverse().Cascade.All();
}
public EvaluationHeadMap()
{
Id(x => x.EvaluationHeadID).GeneratedBy.Identity();
Map(x => x.ManagerID);
Map(x => x.SupervisorID);
Map(x => x.EvaluationStartPeriod);
Map(x => x.EvaluationEndPeriod);
Map(x => x.EmployeeScalePoint);
Map(x => x.KRASignature);
Map(x => x.KRASignatureDate);
Map(x => x.DateCreated);
Map(x => x.DateModified);
HasMany(x => x.KeyResultAreas).KeyColumn("EvaluationHeadID").Cascade.All().Inverse();
HasMany(x => x.Evaluations).KeyColumn("EvaluationHeadID").Inverse().Cascade.All();
HasManyToMany(x => x.TrainingCourses).Table("EvaluationTraining").ParentKeyColumn("EvaluationHeadID").ChildKeyColumn("TrainingCourseID").Cascade.All().AsBag();
References(x => x.Stage).Column("StageID").Cascade.None();
References(x => x.Employee).Column("EmployeeID").Cascade.None();
References(x => x.Employment).Column("EmploymentID").Cascade.None();
//References(x => x.Manager).Column("EmployeeID");
//References(x => x.Supervisor).Column("EmployeeID");
}
public TrainingRouteMap()
{
Id(x => x.TrainingRouteID).GeneratedBy.Identity();
Map(x => x.TrainingRouteDefinition);
Map(x => x.TrainingRouteDescription);
HasMany(x => x.TrainingCourses).KeyColumn("TrainingRouteID").Cascade.AllDeleteOrphan().Inverse();
}
note: i have another query between TrainingCourse and TrainingRoute and it gives no issue at all, even accessing properties through TrainingCourse.TrainingRoute.x pattern. The only difference with this one is that am querying other tables as well.
The TrainingRoute is a reference property of the TrainingCourse (as well as EvaluationHeads). So you have to use JoinQueryOver or JoinAlias for it as well. Below we will create dummy objects to be used for aliasing (all set to null). We also split the joining of the queries, because they result in a references to newly create queries
TrainingCourse trainingCourse = null;
TrainingRoute trainingRoute = null;
EvaluationHead evaluationHead = null;
var query = session.QueryOver<TrainingCourse>(() => trainingCourse);
// here we can work with criteria against the TrainingRoute
var referenceToTraingRouteQuery = query
.JoinQueryOver<TrainingRoute>(p => p.TrainingRoute, () => trainingRoute);
// here we can filter the EvaluationHead collection
var referenceToEvaluationHeadQuery = query // here we start again from the base query
.JoinQueryOver<EvaluationHead>(p => p.EvaluationHeads, () => evaluationHead)
.Where(c => c.EvaluationHeadID == headId);
dto = query
.SelectList(l => l
.Select(() => trainingCourse.TrainingCourseDefn)
.WithAlias(() => d.TrainingCourseDefn)
.Select(() => trainingCourse.IsAvailable)
.WithAlias(() => d.IsAvailable)
// now let's used join alias
.Select(() => trainingRoute.TrainingRouteDefinition)
.WithAlias(() => d.TrainingRouteDefinition))
.TransformUsing(Transformers.AliasToBean<TrainingCourseDTO>())
.List<TrainingCourseDTO>();
Or you can use JoinAlias, see more here 16.4. Associations

nhibernate joinalias doesnt build right query

I get SqlException (The multi-part identifier "packageali1_.PackageID" could not be bound.) whenever I try to execute this query (QueryOver):
var brandsFromBrandsInManufacturer2 =
session.QueryOver<Brand>(() => brandAlias)
.JoinAlias(brand => brand.Package, () => packageAlias)
.Where(
brand =>
brand.ArtificialBrand == 0
)
.And(brand => packageAlias.PackageID
.IsIn(branchPackagesProductGroupShortName.Keys))
.Select(brand => brand.BrandName,
brand => packageAlias.PackageID)
List<object[]>();
It looks like I have error in my mappings:
public class PackageMap : ClassMap<Package>
{
public PackageMap()
{
Table("Packages");
Id(x => x.PackageID).GeneratedBy.Identity();
Map(x => x.Aggregated).CustomType<PackageAggregation>();
References(x => x.DataEndPeriod, "DataEndPeriodID");
References(x => x.Country, "CountryID");
References(x => x.ProductGroup, "ProductGroupID");
HasMany(x => x.PackageHierarchies).KeyColumns.Add("PackageId");
HasMany(x => x.Brands).KeyColumns.Add("PackageId").Inverse();
}
}
public BrandMap()
{
Table("Brands");
CompositeId().KeyProperty(x =>x.BrandId).KeyReference(x => x.Package, "PackageId");
Map(x => x.BrandName);
References(x => x.Manufacturer).Columns(x => x.ManufacturerId).Nullable();
Map(x => x.ArtificialBrand);
}
but I can't find what is wrong. Only thing what I've found is fact, that Brand has classic ID key, but Package has composite key.
PS: SQL query from nHibernate is:
SELECT this_.BrandName as y0_, packageali1_.PackageID as y1_ FROM CD.Brands this_ WHERE this_.ArtificialBrand = #p0 and packageali1_.PackageID in (...)
so as you can see, there is no JOIN.
Could someone point me what is wrong?
The solution here would be to "work" directly with the Key property Package, instead of its alias. So, instead of packageAlias.PackageID, let's navigate there directly through the brand.Package.PackageID.
Also, if we've created so many aliases, let's use them
var brandsFromBrandsInManufacturer2 = session
.QueryOver<Brand>(() => brandAlias)
.JoinAlias(() => brandAlias.Package, () => packageAlias) // use brandAlias
.Where(() => brandAlias.ArtificialBrand == 0 )
// no go to Package directly, not via packageAlias
.And(() => brandAlias.Package.PackageID
.IsIn(branchPackagesProductGroupShortName.Keys))
// the same here, the brand.Package...
.Select(brand => brand.BrandName,
brand => brand.Package.PackageID)
List<object[]>();
Well, the second line, is in fact redundant. so it could be like this:
var list = session
.QueryOver<Brand>(() => brandAlias)
.Where(() => brandAlias.ArtificialBrand == 0 )
.And(() => brandAlias.Package.PackageID
.IsIn(branchPackagesProductGroupShortName.Keys))
.Select(brand => brand.BrandName,
brand => brand.Package.PackageID)
List<object[]>();

Using a null in where clause of rnHibernate

I am trying to filter out the result in the mapping. However I am trying to filter out the nulls from an int field. nHiberate throw an exception. If I use an number it works. Here is the code:
table("products");
Id(x => x.productID);
Map(x => x.canOverwrite);
Map(x => x.format);
Map(x => x.freeShipping);
Map(x => x.height);
Map(x => x.lastUpdated);
Map(x => x.length);
Map(x => x.releaseDate);
Map(x => x.removeDate);
HasMany(x => x.ProductContributors).Where(c => c.sortID != null).KeyColumn("productID").Not.LazyLoad();
Any suggestions on how to get to this to work?
In the contributors I also had a bool value for disabled. I added that to the entity and mapping. Then I filtered by disabled == false. Not really a solution and more of a work around.

Possible to use CustomSqlType with CompositeId?

Working with legacy tables, need to create a CompositeId based on two char(3) fields. Don't see any overloads that make this possible with Fluent.
The mapping I'm attempting looks like this:
CompositeId()
.KeyProperty(x => x.LegacyEntity1Id, "LegacyEntity1Id")
.KeyProperty(x => x.LegacyEntity2Id, "LegacyEntity2Id");
Map(x => x.LegacyEntity1Id).CustomSqlType("char(3)");
Map(x => x.LegacyEntity2Id).CustomSqlType("char(3)");
I've also tried:
CompositeId()
.KeyReference(x => x.LegacyEntity1, "LegacyEntity1Id")
.KeyReference(x => x.LegacyEntity2, "LegacyEntity2Id");
Map(x => x.LegacyEntity1Id).CustomSqlType("char(3)");
Map(x => x.LegacyEntity2Id).CustomSqlType("char(3)");
Both result in the same outcome - the table gets generated with a proper composite id, but both columns are the default nvarchar(255). As a result, the foreign keys fail to generate and I get an exception, since the parent tables are char(3).
Is this not possible to map via Fluent?
If not, is there any real difference in mapping it like this*:
Id(x => x.Id).GeneratedBy.Identity();
Map(x => x.LegacityEntity1Id).CustomSqlType("char(3)");
Map(x => x.LegacityEntity2Id).CustomSqlType("char(3)");
References(x => x.LegacityEntity1).Column("LegacityEntity1Id").UniqueKey("1").Not.Nullable();
References(x => x.LegacityEntity2).Column("LegacityEntity2Id").UniqueKey("1").Not.Nullable();
* I do have the ability to modify the tables slightly (enough to add an identity), since the legacy tables are being ETLed into a local SQL instance.
Or is there another alternative approach? Can't use a HasManyToMany in this case, for what it's worth (will have a payload).
KeyReference will search the map of the referenced entity and uses the sqltype there. go to the referenced entities and specify Id(x => x.Id).Length(3).
This is how to do it in 2017:
CompositeId()
.KeyProperty(
x => x.LegacyEntity1Id,
k => k.ColumnName("LegacyEntity1Id").Type("AnsiString").Length(3))
.KeyProperty(
x => x.LegacyEntity2Id,
k => k.ColumnName("LegacyEntity2Id").Type("AnsiString").Length(3))

Categories

Resources