How to use GroupBy and IQueryable together and map to DTO? - asp.net-mvc

Scenario:
I am in need to fetch some records from Database and I need to group them by CreationDate
IQueryable<AlbumDTO> albums = (from c in context.Albums.where(x =>x.SingerID==1)
.orderBy<x =>x.AlbumDate>.groupBy(x => x.AlbumDate)
select new AlbumsDTO()).Take(10));
But how do I fetch AlbumNames by using this query?
Because if I do
select new AlbumDTO()
{
AlbumName = //nothing comes here and throws error
}

can you try something like this:
context.Albums.Where(x=>x.SinderID==1)
.OrderBy(x =>x.AlbumDate)
.GroupBy(x => x.AlbumDate)
.Select(_ => new AlbumsDTO{AlbumName = _.AlbumName});
?
in my understanding of linq - you are not populating your AlbumDTO objects, but just initializing them.
the way i populate your AlbumDTO objects in the linq query - assumes AlbumName - is a property that has both public setter and public getter:
public class AlbumDTO
{
public string AlbumName {get;set;}
}

Related

How to use COLLATE Latin1_General_bin in Entity framework?

I have to use COLLATE in entity framework query. How to write SQL query equivalent in Entity Framework as show below code?
SQL query:
select * from AspNetUsers order by Email COLLATE Latin1_General_bin
Entity Framework:
using (var db = new testEntities())
{
var appUsers = await db.Users.OrderBy(x => x.Email).ToListAsync();
}
It's possible to use Entity Framework's interception hooks.
The first step it to define an interface:
interface ISortInterceptable
{
IEnumerable<string> AdaptableSortFieldNames { get; set; }
}
Then make your context implement it:
class TestEntities : DbContext, ISortInterceptable
{
...
public IEnumerable<string> AdaptableSortFieldNames { get; set; }
...
}
Next, create a command interceptor:
class SortCommandInterceptor : DbCommandInterceptor
{
public override void ReaderExecuting(DbCommand command,
DbCommandInterceptionContext<DbDataReader> interceptionContext)
{
if (interceptionContext.DbContexts.First() is ISortInterceptable interceptable
&& interceptable.AdaptableSortFieldNames != null)
{
var query = command.CommandText;
foreach (var fieldName in interceptable.AdaptableSortFieldNames)
{
var pattern = $#"(.*\s*ORDER BY\s*.*\.)(\[{fieldName}\])(.*)";
query = Regex.Replace(query, pattern, "$1$2 COLLATE Latin1_General_bin $3");
}
command.CommandText = query;
}
base.ReaderExecuting(command, interceptionContext);
}
}
This is where all the magic happens.
The interceptor first checks if it has to do with a ISortInterceptable (maybe this check can be refined by getting all ISortInterceptables from interceptionContext.DbContexts).
The command text in the command to be executed is analyzed on any occurence of strings like ORDER BY [Alias].[fieldName] where fieldName is a variable. This search pattern is in keeping with the pattern EF always follows to generates queries.
The field name part of the ORDER BY clause, which is in the third group ($2) of the regex match, is extended by the collation phrase.
The replacement is repeated for all field names.
Finally, an example of how to use this interceptor:
DbInterception.Add(new SortCommandInterceptor());
using (var db = new TestEntities())
{
db.AdaptableSortFieldNames = new[] { "LastName", "Email" };
var users = db.AspNetUsers
.OrderBy(u => u.LastName)
.ThenBy(u => U.Email)
.ToList();
}
As always with string manipulation, one caveat: this works in a couple of my own tests, but I can't guarantee it to be rock solid. For one, the sorting fields should be text fields, of course.
One last note. EF core 3 also offers interception hooks that can be used in a similar way.

How can I use IEnumerable.Where().Count() in LINQ query?

In Enitity Framework I'd like to use a linq query in the where clause of another linq query.
public class A {
}
public class B {
public A A { get; set; }
}
public class AB {
public A A { get; set; }
public B B { get; set; }
}
IEnumerable<MassiveObject> filteredData = ... // MassiveObject contains A and some more attributes
var query = from b in db.Bs
.Include("A")
where filteredData.Where(x => x.A.equals(b.A)).Count() > 0 // filteredAs contains an object that contains the same A as the b's A
select new AB {
A = filteredData.Where(a => a.equals(b.A)),
B = b
};
It looks like LINQ doesn't support that. "Unable to create a constant value of type 'MassiveObject'. Only primitive types or enumeration types are supported in this context." Neither the first nor the second use of the nested linq.
Is there another way to this without looping through the query's results after the query was executed?
filteredData is a collection that exists inside the memory of your process. On the other hand, the EF query is translated into SQL that runs on the SQL server.
The SQL server cannot know what data exists in the memory of your process, and even if it could see that memory SQL still has no concept of object instances or iteration. So what you are trying to do is fundamentally impossible.
Linq does not support using an enumeration of an object in a SQL construct because there is no way to make that a SQL stement to start with.
Pull the b's and then filter in that enumeration.
You can't mix in-memory and SQL LINQ queries like this. Instead you need to pull the SQL data into memory before doing the join.
Try something like this instead:
var query =
from b in db.Bs.Include("A").ToArray()
join a in filteredData.Select(x => x.A) on b.A equals a into gas
where gas.Any() // or use gas.Count() > 0
select new AB
{
A = gas.First(),
B = b,
};
Note the .ToArray() call that brings the SQL data into memory.
It isn't very clear what you are trying to achieve, however, previous queries can be used in the current query in various ways e.g.
query2 = source.Where(s => query1.Contains(s));
or using LINQ joins.
In your case itlooks like youare trying to reuse a filter,not a query.
You can achieve this using an extension method from IQueryable<T> to IQueryable<T> or by using expressions.
e.g.
static class MyExtensions
{
public static void IQueryable<T> FilterResults(this IQueryable<T> query)
{
return query.Where(i => i....);
}
}
and then use like so:
query2 = query.FilterResults().Where(...);
For details on the alternative of using Expression Trees see this MSDN article.

Only getting one child observable when I retrieve complete objects graph

I have a large object graph that I want to return to the client (an overview of the entire model) so I decided to send it back as one big object (I'm returning it as the object in question.)
In Breeze however I'm only getting the first object in each dependent object. So for example I have a 'policy' object with two 'vehicle' objects. I only see one vehicle (even when I put a breakpoint at var p = data.results[0]. The json coming back from the call shows two vehicles but breeze is catching only one.
What can I do to get the other ones? Here's the call I'm making:
var getPolicyByPolicyNumber = function (lob, policynumber, policyObservable) {
var params = {};
params['lOBCd'] = lob;
params['policyNumber'] = policynumber;
var query = EntityQuery.from('PolicyInquiry')
.withParameters(params);
return manager.executeQuery(query)
.then(querySucceeded)
.fail(queryFailed);
function querySucceeded(data) {
var p = data.results[0];
p.completeTree(true);
return policyObservable(p);
}
};
And in my breeze controller I have the following:
[System.Web.Http.HttpGet]
public Policy PolicyInquiry(string lOBCd, string policyNumber)
{
UserProfile userProfile = _contextProvider.Context.UserProfiles.SingleOrDefault(u => u.UserName == WebSecurity.CurrentUserName);
var policy = Uow.PolicyServices.GetPolicy(userProfile.BrokerId, userProfile.AgencyId, "csio:" + lOBCd, policyNumber);
return policy;
}
And here's an abbreviated model showing policy and vehicle:
public class Policy
{
public int Id { get; set; }
public string PolicyNumber { get; set; }
[InverseProperty("Policy")]
public ICollection<Vehicle> Vehicles { get; set; }
// other fields removed
}
public class Vehicle
{
public int Id {get; set}
public string ItemId { get; set; }
// other fields removed
//Foreign Keys
public int PolicyId { get; set; }
[IgnoreDataMember]
[ForeignKey("PolicyId")]
[Required]
public virtual Policy Policy { get; set; }
}
Now that I see your model I think I see the issue.
Breeze does not automatically resolve the entity graph on a query. i.e. if you retrieve a Policy, Breeze only returns the Policy instance itself without any navigation properties resolved. This is by design, so that a single query doesn't bring down the entire entity graph.
If you want the values of any navigation properties you have three options, the third of which is probably your best bet. I've taken some liberties in simplifying your model for the purposes of explanation. These all assume that the "Policy" type is actually defined as a Breeze entity type, i.e. has a metadata definition in the Breeze metadataStore.
1) Use an client side EntityQuery.expand clause
var query = EntityQuery.from('Policy')
.expand("Vehicles")
.withParameters(params);
2) Use a server side Include clause
[System.Web.Http.HttpGet]
public IEnumberable<Policy>(string lOBCd, string policyNumber) {
return _contextProvider.Context.Policies.Where(....).Include("Vehicles");
}
3) Use a anonymous result, that contains two known entity types.
[System.Web.Http.HttpGet]
public Object PolicyInquiry(string lOBCd, string policyNumber) {
UserProfile userProfile = _contextProvider.Context.UserProfiles.SingleOrDefault(u => u.UserName == WebSecurity.CurrentUserName);
var policy = Uow.PolicyServices.GetPolicy(userProfile.BrokerId, userProfile.AgencyId, "csio:" + lOBCd, policyNumber);
return new {
Policy = policy,
Vehicles = policy.GetVehicles() // insure that they are actually resolved on the server)
}
return policy;
}
More info here: Navigation Properties
I hope this is clear enough.
Sorry, but without seeing the underlying implementation of "policy" and its metadata, it's hard to tell what's going on. But I can make a general suggestion.
1) If you want to return an aggregate object and have Breeze recognize it's constituent parts, the recommended mechanism is to create a projection and return that. i.e. something like
public IQueryable<Object> CompanyInfoAndOrders() {
return ContextProvider.Context.Customers.Select(c => new { Customer = c, Orders = c.Orders });
}
In this example, providing that Breeze has metadata for the Customer and Order types,
Breeze will deconstruct the result and add the Customer and its orders to the EntityManager, and return a collection of json objects each with a "Customer" and Orders property. The Customer and individual Orders will each have been "adapted" to the current model library as well (i.e. knockout, backbone, or backingStore - for Angular).

Linq casting Issue in EntityFramework

Hi,
I am new to Linq and entity framework. I am doing something like this
I have 3 viewmodel:
1.
public class FlowViewModel
{
..........................
public List<FlowLevelViewModel> Levels { get; set; }
}
public class FlowLevelViewModel
{
.........................
public List<BlockDetailsViewmodel> Blocks { get; set; }
}
public class BlockDetailsViewmodel
{
.......................
}
and from my controller I am calling the datalayer.
var model = new FlowViewModel();
model = dataOb.GetFlowForTheDocument(company, docType);
model = dataOb.GetFlowStageForTheDocument(model);
return model;
and in my datalayer
public FlowViewModel GetFlowStageForTheDocument(FlowViewModel model)
{
var flowlevelviewModel = (from p in dbContext.FlowStages
where p.FlowID == model.FlowId
select new FlowLevelViewModel()
{
.................
Blocks = GetBlockDetailsForTheDocument(p.StageID, .StageType)
}).ToList();
model.Levels = flowlevelviewModel;
return model;
}
public List<BlockDetailsViewmodel> GetBlockDetailsForTheDocument(int StageID, string stageType)
{
var blockDetails = new List<BlockDetailsViewmodel>();
......................................
return blockDetails;
}
While I am running the program I am getting this error:
**NotSupportedException Was unhandled by user Code**
LINQ to Entities does not recognize the method 'System.Collections.Generic.List`1[SEADViewModel.BlockDetailsViewmodel] GetBlockDetailsForTheDocument(Int32, System.String)' method, and this method cannot be translated into a store expression.
My project is in production stage so I have no time at all. Does anyone know what I am doing wrong?
This should solve your problem:
var data = (from p in dbContext.FlowStages
where p.FlowID == model.FlowId
select p).ToList();
var flowlevelviewModel = (from p in data
select new FlowLevelViewModel()
{
.................
Blocks = GetBlockDetailsForTheDocument(p.StageID, .StageType)
}).ToList();
Note that this will evaluate the query at the first ToList(). If you need to run the entire query at once, you need to build a simple LINQ expression, you can't use your method GetBlockDetailsForTheDocument inside the query. See #Tilak's answer for a link to supported build in methods.
You are using Linq to Entities.
It does not support all the functions. List of supported and non supported functions
You need to write custom model defined function GetBlockDetailsForTheDocument to use it in LINQ query.

LINQ to SQL in ASP.NET MVC and Repository pattern

I'm trying to follow a tutorial from the Asp.NET MVC website which uses LINQ to Entities but I decided to use LINQ to SQL instead. I'm at the point where a new table is created called Groups which has a relationship to the Contacts table. Esentially it's a One to Many relationship where a Group can have many contacts and a Contact can only have 1 Group. Please see below the example code with CRUD operations.
I'm not sure how to implement this in LINQ to SQL. For example, how do you do this in LINQ to SQL:
return _entities.GroupSet.Include("Contacts").FirstOrDefault();
Are you supposed to do a JOIN for the two tables or is there another way?
Example CODE:
using System.Collections.Generic;
using System.Linq;
using System;
namespace ContactManager.Models
{
public class EntityContactManagerRepository : ContactManager.Models.IContactManagerRepository
{
private ContactManagerDBEntities _entities = new ContactManagerDBEntities();
// Contact methods
public Contact GetContact(int id)
{
return (from c in _entities.ContactSet.Include("Group")
where c.Id == id
select c).FirstOrDefault();
}
public Contact CreateContact(int groupId, Contact contactToCreate)
{
// Associate group with contact
contactToCreate.Group = GetGroup(groupId);
// Save new contact
_entities.AddToContactSet(contactToCreate);
_entities.SaveChanges();
return contactToCreate;
}
public Contact EditContact(int groupId, Contact contactToEdit)
{
// Get original contact
var originalContact = GetContact(contactToEdit.Id);
// Update with new group
originalContact.Group = GetGroup(groupId);
// Save changes
_entities.ApplyPropertyChanges(originalContact.EntityKey.EntitySetName, contactToEdit);
_entities.SaveChanges();
return contactToEdit;
}
public void DeleteContact(Contact contactToDelete)
{
var originalContact = GetContact(contactToDelete.Id);
_entities.DeleteObject(originalContact);
_entities.SaveChanges();
}
public Group CreateGroup(Group groupToCreate)
{
_entities.AddToGroupSet(groupToCreate);
_entities.SaveChanges();
return groupToCreate;
}
// Group Methods
public IEnumerable<Group> ListGroups()
{
return _entities.GroupSet.ToList();
}
public Group GetFirstGroup()
{
return _entities.GroupSet.Include("Contacts").FirstOrDefault();
}
public Group GetGroup(int id)
{
return (from g in _entities.GroupSet.Include("Contacts")
where g.Id == id
select g).FirstOrDefault();
}
public void DeleteGroup(Group groupToDelete)
{
var originalGroup = GetGroup(groupToDelete.Id);
_entities.DeleteObject(originalGroup);
_entities.SaveChanges();
}
}
}
You need to specify some DataLoadOptions to create the join for you:
So to do this, you have to create a DataContext for each type of query with the correct DataLoadOptions:
var db = new WhateverDbDataContext();
DataLoadOptions options = new DataLoadOptions();
db.LoadOptions = options;
options.LoadWith(x => x.Contacts);
return db.SomeTable.FirstorDefault();
Linq to sql does not support the Include method. If you don't care if the relationship is lazy loaded, then you don't have to do anything. If you want it to be eager loaded, then you have use the more convoluted DataLoadOptions.
See this article:
http://blog.stevensanderson.com/2007/12/02/linq-to-sql-lazy-and-eager-loading-hiccups/

Resources