Nhibernate and indexed view - c#

I have an Album entity which has IList<Photo> in it. I want to select all my albums with count of photos with one fast query using NHibernate. Before migrating to NH I had a query using an indexed view:
SELECT a.*, t.PhotoCount
FROM dbo.Album a
LEFT JOIN dbo.vw_AlbumPhotoCount t ON t.AlbumID = a.AlbumID
How can I use this view (vw_AlbumPhotoCount) in NHibernate to speed up the query?
UPDATE:
I mapped a simple <one-to-one/> entity as Alex advised and it worked for me. One downside of this solution - as one-to-one properties cannot be loaded lazily I always get LEFT JOIN when fetching album by id. I couldn't map this entity as <many-to-one/> property, I'm not sure why maybe because the view doesn't have its own ID property. Anyway ofter mapping it as <many-to-one/> I got null in it after fetching an album
UPDATE 2:
I've reviewed my architecture and decided to remove the view. The best way in this particular situation is using NH caching system instead of indexed view

Your best bet may be to map a simple entity to your PhotoCount view, and then set up a relationship to that entity through ordinary means. Just make sure you don't cache these objects, because they will never actually get updated.

a Property on the Album with a formula
// Fluent Mapping
Map(x => x.PhotoCount).Formula("SELECT t.PhotoCount FROM dbo.vw_AlbumPhotoCount t ON t.AlbumID = AlbumID");
// xml mapping
<property name="PhotoCount" formula="SELECT t.PhotoCount FROM dbo.vw_AlbumPhotoCount t ON t.AlbumID = AlbumID">
var albums = session.QueryOver<Album>().List();

Related

C#, EF: Map [NotMapped] value from Sql Query

I'm using Entity Framework. I currently have an attribute that is labeled [NotMapped] in my model class. I'm also using a query to bring back that value (from a view, which is why it's not mapped).
var list = context.Database
.SqlQuery<SomeModel>("SELECT NonMappedField, anotherfield FROM SomeView")
.ToList()
Is there a way I can hint to C# that for this instance, it should map the column from the raw query to my models?
I would have more things showing what I've tried, but I don't have the slightest clue of what to do next, other than build my own mapper and that seems like a very brittle solution.
Possible X/Y Problem:
My a data model has a Parent/Child relationship. The Child can be a child of multiple models,necessitating the use of a join table ParentChildJoin. When I do
context.Database.Parent.Where...Include( n => n.Children ).ToList();
I run into query timeouts for a pathetically small number of rows. So I had the bright idea of joining the ParentChildJoin table with the Child table in a View and retrieving the children that way. This works, but I need some way to map the retrieved Child objects to their Parent.
This is where the NotMapped field comes in. I can create a NonMapped field on my model, and then when I retrieve from my View, I can store the ParentId there. From there, I can associate the Child objects with the correct parent.
So that's how I go here.
Either the field is mapped or it isn't, you can't have it both ways!
Take a look at AutoMapper and the AutoMapperEF extension. The EF extension is clever enough to realise that a model that only has a selection of fields from a query will only have those fields in the generated SELECT. You could have several different models for the same query, each only returning the fields required for that model.
What you can do (without changing model) is to concatenate NonMappedField+"_"+anotherfield as anotherfield before load.
After FromSql load, you can split NonMappedField and anotherfield back.
var query = "SELECT [Id], CONVERT(VARCHAR(1024),[NonMappedField]+'|'+[anotherfield]) AS [anotherfield] FROM myView";
var list = _context.SomeModels.FromSql(query)
.Select(i => new SomeModel {
Id = i.Id,
NonMappedField = i.anotherfield.Substring(0, i.anotherfield.IndexOf('|')),
anotherfield = i.anotherfield.Substring(i.anotherfield.IndexOf('|')+1)
}).ToList();

Entity Framework Linq query unrelated child tables

I am using Entity Framework 6.1.3 to generated the entities and data model.
If I have two tables: Orders -> OrderDetails, with a relation between them (OrderId), then I can get all the orders and related OrderDetails with the following query
dbContext.Order().Include(a => a.OrderDetails);
But if I created a view (vOrder) for Orders, then there is no direct relation between vOrder and OrderDetails in the model, though I can link them together with joins on OrderId. How could I still get all the data from vOrder and related OrderDetails. The following query doesn't work unless I add all the navigation properties manually.
dbContext.vOrder().Include(a => a.OrderDetails);
Is there a simple LINQ query to accomplish the intended query?
Thanks for your help.
Do a manual join and return an anonymous object that contains both.
Something like:
dbContext.vOrder
.GroupJoin(
dbContext.OrderDetails,
v=>v.orderid,
od=>o.orderid,
(v,od)=>new {v=v,od=od});
Of course, you could just add the appropriate naviation properties on to vOrder and do exactly what you said.
Why not just include more columns in the view (or create another view that has all the required data, if you don't want to modify the first one)?

Listing entities pointed by foreign keys in Entity Framework

I have two Entities, let's say Car and Photo.
Each photo has foreign key to Car, so each car has set of its photos.
I want to list some subset of cars and for each listed car I want to list all of each photos.
How can I do this in Entity Framework with 1 db query?
I know from the beginning that I would need photos.
My code for now look like:
var carList = CarEntities.Where(...).ToList();
foreach(var car in carList){
var photoList = car.Photos.ToList();
}
I think, EF would do separately db query for each car.
You can tell Entity Framework in include Photos when querying Cars.
var carList = CarEntities.Include(c => c.Photos).Where(...).ToList();
ckal's answer is pretty close except use include in the end otherwise EF may not always include it (cant recall exact reason at the moment),
var carList = CarEntities.Where(...).Include(c => c.Photos).ToList();
Edit: Here's the reason... Entity Framework Include() is not working
"Select new" is what you likely want to do. Create a new class called CarWithPhotos and use that to return a set of results:
var carWithPhotos = from car in CarEntities
where (...)
select new CarWithPhotos(car, car.Photos.ToList());
As I understand it, this compiles to one a single database trip, which I think is what you're after.
Edit: I've used this technique when the objects I'm querying are large and I don't always want to retrieve an entire "Car" object for example.

Fluent nHibernate Join

I have an entity that maps to a table called Rule. The table for this entity has an FK to another Table called Category. I'm trying to figure out how to pull in a property from Category in my Rule entity. I'm pretty sure I want to use a join in my entity mapping, but I can't figure out how to configure it so that it works. Here is my mapping:
Join("Category", x =>
{
x.Map(i => i.CategoryName, "Name");
x.KeyColumn("CategoryId");
x.Inverse();
});
Here is the SQL that it's generating...
SELECT ...
FROM Rule rules0_ left outer join Category rules0_1_ on rules0_.Id=rules0_1_.CategoryId
WHERE ...
Here is the SQL that I want.
SELECT ...
FROM Rule rules0_ left outer join Category rules0_1_ on rules0_.CategoryId=rules0_1_.Id
WHERE ...
I can't seem to find anything on the JoinPart that will let me do this. Subselect looks promising from the little bit of documentation I've found, but I can't find any examples of how to use it. Any advice on this problem would be much appreciated. Thanks!
"Join" is poorly named. a "join" in an NHibernate mapping implies a zero-to-one relationship based on a relation of the primary keys of the two tables. You would use a join if, for instance, you had a User table and a UserAdditionalInfo table, with zero or one record per User. The UserAdditionalInfo table would likely reference the PK from User as both a foreign key and its own primary key. This type of thing is common when a DBA has to religiously maintain a schema for a legacy app, but a newer app needs new fields for the same conceptual record.
What you actually need in your situation is a References relationship, where a record has a foreign key relationship to zero or one other records. You'd set it up fluently like so:
References(x=>Category)
.Column("CategoryId")
.Inverse()
.Cascade.None();
The problem with this is that Category must now be mapped; it is a separate entity which is now related to yours. Your options are to live with this model, to "flatten" it by making the entity reference private, changing the mapping to access the entity as such, and coding "pass-throughs" to the properties you want public, or by using a code tool like AutoMapper to project this deep domain model into a flat DTO at runtime for general use. They all have pros and cons.

Eager load a self-referencing table

I have a standard self referencing table of Categories. In my entity model I have made associations Children and Parent. Is it possible to load the whole Category object without lazy loading?
if I use the code below, it loads only to the second level.
db.Categories.MergeOption = System.Data.Objects.MergeOption.NoTracking;
var query = from c in db.Categories.Include("Children")
where c.IsVisible == true
orderby c.SortOrder, c.Id
select c;
Is it possible to load references if I have all the category objects already loaded?
One method to load it is to add the Children property multiple times
db.Categories.Include("Children.Children.Children.Children.Children")
but this generates a very long insane T-SQL code and also it doesn't do what I want.
No, it isn't possible. Consider: All LINQ to Entities queries are translated into SQL. Which SQL statement includes an unlimited depth in a self-referencing hierarchy? In standard SQL, there isn't one. If there's an extension for this in T-SQL, I don't know what it is, and I don't think EF providers do, either.
Ok, you might consider using Load method.
if (!category.Children.IsLoaded)
category.Children.Load();
Of course, category entity need to be tracked by ObjectContext.
There is better explanation here how-does-entity-framework-work-with-recursive-hierarchies-include-seems-not-to.
One way I have used to implement that if I have several entities I want to get all children in self-referencing table is to use recursive cte and stored procedure to get their ids using Entity FrameWork :
Here is the code using Entity Framework and code first approach

Categories

Resources