Linq for NHibernate and fetch mode of eager loading - linq

Is there a way to set the fetchmode to eager for more than one object using linq for nhibernate. There seems to be an expand method which only allows me to set one object. However I need to set it for more than one object. Is this possible? Thanks

The new Linq provider does it a little differently:
var customers = session.Query<Customer>().Fetch(c => c.Orders).ToList();
More here:
http://mikehadlow.blogspot.com/2010/08/nhibernate-linq-eager-fetching.html

just use it more then once.
IList<Entity> GetDataFromDatabase()
{
var query = session.Linq<Entity>();
query.Expand("Property1");
query.Expand("Property2");
return query.ToList();
}

As far as I can see, this is not equivalent: SetFetchMode hydrates an objects tree and the Expand method retrieves a cartesian product.

In contiune to #Mike Hadlow answer, fetching next level (grandchildren) you need to do:
var customers = session.Query<Customer>()
.FetchMany(c => c.Orders)
.ThenFetchMany(o => o.OrderLines).ToList();

Related

EF4.1 LINQ, selecting all results

I am new to LINQ queries and to EF too, I usually work with MySQL and I can't guess how to write really simples queries.
I'd like to select all results from a table. So, I used like this:
ZXContainer db = new ZXContainer();
ViewBag.ZXproperties = db.ZXproperties.All();
But I see that I have to write something inside All(---).
Could someone guide me in how could I do that? And if someone has any good link for references too, I thank so much.
All() is an boolean evaluation performed on all of the elements in a collection (though immediately returns false when it reaches an element where the evaluation is false), for example, you want to make sure that all of said ZXproperties have a certain field set as true:
bool isTrue = db.ZXproperties.All(z => z.SomeFieldName == true);
Which will either make isTrue true or false. LINQ is typically lazy-loading, so if you're calling db.ZXproperties directly, you have access to all of the objects as is, but it isn't quite what you're looking for. You can either load all of the objects at the variable assignment with an .ToList():
ViewBag.ZXproperties = db.ZXproperties.ToList();
or you can use the below expression:
ViewBag.ZXproperties = from s in db.ZXproperties
select s;
Which is really no different than saying:
ViewBag.ZXproperties = db.ZXproperties;
The advantage of .ToList() is that if you are wanting to do multiple calls on this ViewBag.ZXproperties, it will only require the initial database call when it is assigning the variable. Alternatively, if you do any form of queryable action on the data, such as .Where(), you'll have another query performed, which is less than ideal if you already have the data to work with.
To select everything, just skip the .All(...), as ZXproperties allready is a collection.
ZXContainer db = new ZXContainer();
ViewBag.ZXproperties = db.ZXproperties;
You might want (or sometimes even need) to call .ToList() on this collection before use...
You don't use All. Just type
ViewBag.ZXproperties = db.ZXproperties;
or
ViewBag.ZXproperties = db.ZXproperties.ToList();
The All method is used to determine if all items of collection match some condition.
If you just want all of the items, you can just use it directly:
ViewBag.ZXproperties = db.ZXproperties;
If you want this evaluated immediately, you can convert it to a list:
ViewBag.ZXproperties = db.ZXproperties.ToList();
This will force it to be pulled across the wire immediately.
You can use this:
var result = db.ZXproperties.ToList();
For more information on linq see 101 linq sample.
All is some checking on all items and argument in it, called lambda expression.

Selecting single items from MVC enumerable models

when using a MVC 3 collection that uses IEnumerable, is there a way to make small queries work to find single values? I've been experimenting with little success.
I have a collection of settings that have descriptions and settings. The problem is exposing one of them, as each is unique. I've tried something like this:
var appl = _service.GetSettings(id, app); //Call to service layer & repository
appl.Select(a => a.setting_value.Where(a.setting_name.StartsWith("Login")));
With little success (unless I'm missing something). Is it possible to select one item from an enumerable collection and either pass it to a ViewBag or ViewData object? What I would like to do is something like the following:
var appl = _service.GetSettings(id, app); //Call to service layer & repository
ViewBag.Login = appl.Select(a => a.setting_value.Where(a.setting_name.StartsWith("Login")));
And pass this to the view, since I have a view that now combines a collection with single values.
The following seems to work within the view:
Application Name #Html.TextBox("application_name", #Model.FirstOrDefault().app_name)
But I'm not sure if this violates separation of concerns. Am I on the wrong path here? Thank you!
EDIT: Here is what I needed. The answers below got me very very close +1 +1
ViewBag.Login = appl.Where(a => a.setting_name.StartsWith("Login")).FirstOrDefault().setting_value
ViewBag.Login = appl.Select(a => a.setting_value.Where(a.setting_name.StartsWith("Login"))).FirstOrDefault();
This will select the first object that matches your criteria and return a single result or null
var appl = _service.GetSettings(id, app);
ViewBag.Login = appl
.Where(a => a.setting_name.StartsWith("Login"))
.FirstOrDefault();

Entity Framework LINQ Query using Custom C# Class Method - Once yes, once no - because executing on the client or in SQL?

I have two Entity Framework 4 Linq queries I wrote that make use of a custom class method, one works and one does not:
The custom method is:
public static DateTime GetLastReadToDate(string fbaUsername, Discussion discussion)
{
return (discussion.DiscussionUserReads.Where(dur => dur.User.aspnet_User.UserName == fbaUsername).FirstOrDefault() ?? new DiscussionUserRead { ReadToDate = DateTime.Now.AddYears(-99) }).ReadToDate;
}
The linq query that works calls a from after a from, the equivalent of SelectMany():
from g in oc.Users.Where(u => u.aspnet_User.UserName == fbaUsername).First().Groups
from d in g.Discussions
select new
{
UnReadPostCount = d.Posts.Where(p => p.CreatedDate > DiscussionRepository.GetLastReadToDate(fbaUsername, p.Discussion)).Count()
};
The query that does not work is more like a regular select:
from d in oc.Discussions
where d.Group.Name == "Student"
select new
{
UnReadPostCount = d.Posts.Where(p => p.CreatedDate > DiscussionRepository.GetLastReadToDate(fbaUsername, p.Discussion)).Count(),
};
The error I get is:
LINQ to Entities does not recognize the method 'System.DateTime GetLastReadToDate(System.String, Discussion)' method, and this method cannot be translated into a store expression.
My question is, why am I able to use my custom GetLastReadToDate() method in the first query and not the second? I suppose this has something to do with what gets executed on the db server and what gets executed on the client? These queries seem to use the GetLastReadToDate() method so similarly though, I'm wondering why would work for the first and not the second, and most importantly if there's a way to factor common query syntax like what's in the GetLastReadToDate() method into a separate location to be reused in several different other LINQ queries.
Please note all these queries are sharing the same object context.
I think your better of using a Model Defined Function here.
Define a scalar function in your database which returns a DateTime, pass through whatever you need, map it on your model, then use it in your LINQ query:
from g in oc.Users.Where(u => u.aspnet_User.UserName == fbaUsername).First().Groups
from d in g.Discussions
select new
{
UnReadPostCount = d.Posts.Where(p => p.CreatedDate > myFunkyModelFunction(fbaUsername, p.Discussion)).Count()
};
and most importantly if there's a way to factor common query syntax like what's in the GetLastReadToDate() method into a separate location to be reused in several different places LINQ queries.
A stored procedure would probably be one way to store that 'common query syntax"...EF, at least 4.0, works very nicely with SP's.

Entity Framework - LinQ projection problem

I want to create an Entity Object from a LinQ statement, but I don't want to load all its columns.
My ORDERS object has a lot of columns, but I just want to retrieve the REFERENCE and OPERATION columns so the SQL statement and result will be smaller.
This LinQ statement works properly and loads all my object attributes:
var orders = (from order in context.ORDERS
select order);
However the following statement fails to load only two properties of my object
var orders = (from order in context.ORDERS
select new ORDERS
{
REFERENCE = order.REFERENCE,
OPERATION = order.OPERATION
});
The error thrown is:
The entity or complex type
'ModelContextName.ORDERS' cannot be
constructed in a LINQ to Entities
query.
What is the problem? Isn't it possible to partially load an object this way?
Thank you in advance for your answers.
ANSWER
Ok I should thank you both Yakimych and Dean because I use both of your answers, and now I have:
var orders = (from order in context.ORDERS
select new
{
REFERENCE = order.REFERENCE,
OPERATION = order.OPERATION,
})
.AsEnumerable()
.Select(o =>
(ORDERS)new ORDERS
{
REFERENCE = o.REFERENCE,
OPERATION = o.OPERATION
}
).ToList().AsQueryable();
And I get exactly what I want, the SQL Statement is not perfect but it returns only the 2 columns I need (and another column which contains for every row "1" but I don't know why for the moment) –
I also tried to construct sub objects with this method and it works well.
No, you can't project onto a mapped object. You can use an anonymous type instead:
var orders = (from order in context.ORDERS
select new
{
REFERENCE = order.REFERENCE,
OPERATION = order.OPERATION
});
The problem with the above solution is that from the moment you call AsEnumerable(), the query will get executed on the database. In most of the cases, it will be fine. But if you work with some large database, fetching the whole table(or view) is probably not what you want. So, if we remove the AsEnumerable, we are back to square 1 with the following error:
The entity or complex type 'ModelContextName.ORDERS' cannot be constructed in a LINQ to Entities query.
I have been struggling with this problem for a whole day and here is what I found. I created an empty class inheriting from my entity class and performed the projection using this class.
public sealed class ProjectedORDERS : ORDERS {}
The projected query (using covariance feature):
IQueryable<ORDERS> orders = (from order in context.ORDERS
select new ProjectedORDERS
{
REFERENCE = order.REFERENCE,
OPERATION = order.OPERATION,
});
Voilà! You now have a projected query that will map to an entity and that will get executed only when you want to.
I think the issue is creating new entities within the query itself, so how about trying this:
context.ORDERS.ToList().Select(o => new ORDERS
{
REFERENCE = o.REFERENCE,
OPERATION = o.OPERATION
});

Can you sort Typed DataSet DataTables with Linq OrderBy?

I have a Typed DataSet DataTable which inherits TypedTableBase<T>, which in turn implements IEnumerable<T>. I can't seem to get this to work.
myDataTable.OrderBy(x => x.ID).ThenBy(y => y.ID2);
Instead I have to assign this statement to an IEnumerable(or List), then refill my DataTable manually with the newly ordered IEnumerable before I commit. Is this how it is intended to be? I've thought about creating my own extension method that will empty/refill my DataTables, but would this be wise?
Note: Typically I only need to sort for viewing purposes using DataView. But in this case I have a custom routine that must create a new access database with sorting requirements, which means I need to sort the actual DataTable so that I may re-commit it.
Thank you.
In order to do what you want, you must add the following reference to your project:
System.Data.DataSetExtensions
Once you have that added, you can order your DataTable like this:
var query = myDataTable.OrderBy(x => x.ID).ThenBy(y => y.ID2);
// use the DataView generated from the LINQ query
DataView dtv = query.AsDataView();
In order to iterate through the DataView, you can do the following:
var dtv = query.AsDataView();
foreach(DataRowView rw in dtv)
{
// you can also cast back to the typed data...
MyCustomRowType typedRow = (MyCustomRowType) rw.Row;
// do something here...
}
Alternatively you can typecast via LINQ this way:
var dtv = query.AsDataView().Cast<MyCustomRowType>();
// rowItem is of type MyCustomRowType...
foreach(var rowItem in dtv)
{
// do something here...
}
Linq extension methods do not alter the source enumerable.
var numbers = new int[]{1,2,3};
var reversed = numbers.OrderByDescending(x=>x);
foreach(var number in reversed)
Console.Write(number); // 321
foreach(var number in numbers)
Console.Write(number); // 123
If you want to sort a DataTable, you should be using DataViews. You create a view on your DataTable, then apply a Sort or Filter to it, then bind against it. Keep in mind DataSets are an older technology and not quite up to date on the latest and the greatest. A "newer" approach would be to use the Entity Framework.

Resources