NHibernate mapping by code - composite unique index - c#

How do I create a composite UNIQUE constaint on 3 properties of a class?
It needs to allow NULL as a legitimate value.

This should be one of the ways to go about it..
mapper.Class<MyClass>(ca =>
{
ca.Property(x => x.Property1, map => map.UniqueKey("UQ_ComposedUniqueKey"));
ca.ManyToOne(x => x.FKField1, map => { map.UniqueKey("UQ_ComposedUniqueKey"); map.NotNullable(false); });
});
You can combine many properties or FKs in a single unique key.

Related

Select a specific column with multiple includes in Entity Framework

I'm trying to get specific columns from a context with several includes, but when I try:
Context.Include(i => i.c)
.Include(i => i.l).Select(s=> new LocationCatalog { Name = s.Name})
.Include(i => i.p)
.Include(i => i.li)
.Include(i => i.pcl)
VS throws an error after the select.
How can I achieve this? I want to specify the columns for each include.
The error says that for example: i.p doesn't contains definition for i.l
That's not possible with Entity Framework. You either include the entire table (with Include, as you are doing) or you don't include it at all.
If you want to load only specific columns, you can do this, but see how it's a manual process:
Context
.Select(i => new YourType
{
c = i.l,
l = i.l,
x = new X
{
a = i.x.a // only the properties you want here
}
...
});
The moment you use Select, Include is completely ignored, so you cannot use both.

Issue with many-to-many query with linq to entities

I've got a table
Application
ApplicationID,
NAme
ApplicationSteps
AplicationStepID,
AplicationID,
StepID
ApplicationStepCriterias
ApplicationStepID,
CriteriaID
So I've got one SelectedCriteriaID - a user choose from a dropdown one criteria and he wants all the applications which has this SelectedCriteriaID in the table ApplicationStepCriterias
I tried
var ds = context.Applications
.Where(a => a.ApplicationSteps
.Select(x=>x.ApplicationStepCriterias
.Select(t=>t.CriteriaId))
.Contains(SelectesdCriteria));
But as I have as result IEnumerable<IEnumerable<int>> I cannot use Contains
Just I get a list of all the CriteriaIds for each ApplicationStep(also a sequence). Just I cannot think of way to get in one list all the CriteriIds.
First, let me try to get the names right. This is not a pure many-to-many association, because the junction class is part of the class model. It is what I unofficially call a 1-n-1 association. So you have
Application -< ApplicationSteps >- ApplicationStepCriterias
I'd strongly recommend to use singular names for your classes ...
Application -< ApplicationStep >- ApplicationStepCriterion
... so you can use plural for collection property names without getting confused.
If I'm right so far, you query should be
context.Applications
.Where(a => a.ApplicationSteps
.Any(x => selectedCriteria
.Contains(x.ApplicationStepCriterion.CriteriaId));
(and I'd also prefer CriterionId, probably referring to a Criterion class)
You may try something like this:
var applicationStepIds = context.ApplicationStepCriterias
.Where(i => i.CriteriaID == selectedCriteria)
.Select(i => i.ApplicationStepID)
.Distinct();
var applicationIds = context.ApplicationSteps
.Where(i => applicationStepIds.Contains(i.AplicationStepID))
.Select(i => i.AplicationID)
.Distinct();
var result = context.Applications.Where(i => applicationIds.Contains(i.ApplicationId));

Linq include only max row

I'm pulling items from a table that i'm including another table.
When including, there is likely multiple rows belonging to that item in the included table but I only want to include the row that contains the max value of a column.
items.AddRange(db.AuctionItems
.Include(f => f.AuctionBids.Max().Bid)
.OrderBy(x => x.Item));
Also tried
items.AddRange(db.AuctionItems
.Include(f => f.AuctionBids.Max(y => y.Bid))
.OrderBy(x => x.Item));
Error
The Include path expression must refer to a navigation property defined on the type. Use dotted paths for reference navigation properties and the Select operator for collection navigation properties.
Added info
Table AuctionItems
ID
Name
.....
Table AuctionBids
ID
ItemID
Bid
....
So I want to pull all items and include only the row that contains the highest bid for that item.
You may do the following:
db.AuctionItems
.Select(s => new{ai = s, bid = s.AuctionBids.OrderByDescending(o => o.Bid).FirstOrDefault()})
.AsEnumerable()
.Select(s => s.ai)
Using this approach you are loading only required AuctionBids into context and EF will do the mapping to appropriate AuctionItems for you.

AutoMapper ignore properties while mapping a list

Is it possible in AutoMapper to ignore certain properties while mapping a list?
For example, I have two classes Metadata and MetadataInput.
Both have the same fields except for destination, "MetadataInput", which has an extra field.
Mapper.CreateMap <IList<Metadata>, IList<MetadataInput>>()
I've tried to use the formember option but it generates errors, probably because the property cannot be used when you want to map a list? If yes, is there alternative solution?
As Darin Dimitrov suggested, you should not try and map lists or collections.
If you have a 1 -> 1 relationship between them all, just make a map like:
Mapper.CreateMap<Metadata, MetadataInput>().ForMember(s => s.Property, t => t.Ignore());
Then you could use your list and select it to the other list.
var metadataList = new List<Metadata>();
var meatadataInputList = metadataList.Select(p => Mapper.Map<MetadataInput>(p).ToList();
Use this mapper configuration to get the desired result:
Mapper.CreateMap<Output, Input>().ForMember(s => s.InputProperty1, t => t.Ignore());
Mapper.CreateMap<Output, Input>().ForMember(s => s.InputProperty2, t => t.Ignore());
Mapper.CreateMap<Input, Output>();
listOfItems = Mapper.Map<List<Input>, List<Output>>(InputListObject);
As others suggested, we should avoid mapping lists and collections. In order to ignore all the unmapped properties, the following worked out for me.
CreateMap<Metadata, MetadataInput>()
.ForMember(dest => dest.Id, o => o.MapFrom(src => src.sourceIdentifier))
.ForMember(dest => dest.Name, o => o.MapFrom(src => src.sourceName))
.ForAllOtherMembers(opts => opts.Ignore());
ForAllOtherMembers should be the last in the method chain.
Thanks for the useful comments.
Because both lists are already made before mapping I've done it this way:
Gets the list from the db:
List<Metadata> metadatas = _Metadataservice.GetList(_Collectionservice.Get("Koekelare").ID).ToList();
Create the mapper (thanks for pointing out my mistake):
Mapper.CreateMap<Metadata, MetadataInput>().ForMember(s => s.Property, t => t.Ignore());
Make a new list and map the new (single) values one by one:
List<MetadataInput> meta = new List<MetadataInput>();
for (int i = 0; i < e.Count; i++)
{
meta.Add(Mapper.Map<Metadata, MetadataInput>(metadatas[i], input.Metadatas[i]));
}
Could someone confirm this is a good way?

Entity Framework Code First One to One relationship on composite key

Basically what I am trying to achieve is I have three tables, one parent will always have an entry in it and only one of the other two tables will be populated. The complexity that I am dealing with is that the primary key for the tables is the combination of two fields
ParentTable
-----------
UniqueID
OwnerID
[Some more fields]
ChildTable1
-----------
UniqueID
OwnerID
[Some more fields]
ChildTable2
-----------
UniqueID
OwnerID
[Some more fields]
I was wondering if anyone has any suggestions on how best to do this through EF Code First preferably using the Fluent API.
You just need to define that the primary keys are composite...
modelBuilder.Entity<Parent>().HasKey(p => new { p.UniqueID, p.OwnerID });
modelBuilder.Entity<Child1>().HasKey(c => new { c.UniqueID, c.OwnerID });
modelBuilder.Entity<Child2>().HasKey(c => new { c.UniqueID, c.OwnerID });
...and then define the two one-to-one relationships:
modelBuilder.Entity<Parent>()
.HasOptional(p => p.Child1)
.WithRequired(); // or .WithRequired(c => c.Parent)
modelBuilder.Entity<Parent>()
.HasOptional(p => p.Child2)
.WithRequired(); // or .WithRequired(c => c.Parent)
You cannot define a constraint though (except probably by defining a trigger in the database) that would ensure that a given parent may only refer to one of the two children, but not to both. You must handle this restriction in your application's business logic.

Categories

Resources