Filtering entity with another entity - c#

Im trying to filter an entity with another entity with this approach:
[HttpGet]
public async Task<IActionResult> GetViewIO()
{
int uid = (int)HttpContext.Session.GetInt32("userId").Value;
if(uid == 2)
{
uid = 33;
}
var listAeGrp = _context.ListofAE.FromSql($"Execute ListOfAe {uid}");
var _orders = _context.OrderHeaderView.FromSql(#"OrderHeaderView").OrderByDescending(f => f.id).OrderBy(p => p.platform_id);
var orders = await _orders.Where(x => listAeGrp.Any(y => y.id == x.created_by)).ToListAsync();
return Json(orders);
}
So basically, Im getting the values of listAeGrp and _orders using FromSQL and a stored procedure in MSSQL. listAeGrp relies on the current user that is logged in while _orders has a plain select of data created.
With this separate variable I can check that they have values but when im doing the filtering using .Any of linq, an error is returned:
Could not parse expression 'value(Microsoft.Data.Entity.Query.Internal.EntityQueryable`1[DigitalMVC.API.Models.listofAE]).FromSql("Execute ListOfAe 33", value(System.Object[]))': This overload of the method 'Microsoft.Data.Entity.RelationalQueryableExtensions.FromSql' is currently not supported.
Im currently using VS2015, dnx4.5.1
So my questions is:
Where did I go wrong? Im fairly new to MVC and Linq.
Is there other way to do this?
Thank you so much for the help!

What I did is instead of using an Entity to filter another entity, I created a function that will return a list of int
public List<int>ListOfUsers(int uid)
{
List<int> listOfAeGroup = new List<int>();
var listAeGrp = _context.ListofAE.FromSql($"Execute ListOfAe {uid}");
listOfAeGroup = listAeGrp.Select(x => x.id).ToList();
return listOfAeGroup;
}
Then I used the returned function and use it this way:
List<int> allowedUserId = ListOfUsers(uid);
var orders = await _context.OrderHeaderView.FromSql(#"OrderHeaderView").Where(x => allowedUserId.Contains(x.created_by)).OrderByDescending(f => f.id).OrderBy(p => p.platform_id).ToListAsync();
return Json(orders);

Related

Obtaining entities from DbSet from a list of matching objects

I'm using Entity Framework Core 6 and I want to find a series of entities in a DbSet. The entities I want to obtain are the ones match some properties in a list of input objects.
I've tried something like this:
public IEnumerable<MyEntity> FindEntities(IEnumerable<MyEntityDtos> entries)
{
return dbContext.MyDbSet.Where(r => entries.Any(e => e.Prop1 == r.Prop1 && e.Prop2 == r.Prop2));
}
But I get the classic EF Core exception saying that my LINQ cannot be translated to a database query (the problem in particular is the entries.Any(...) instruction)
I know I can just loop over the list of entries and obtain the entities one by one from the DbSet, but that is very slow, I was wondering if there was a more efficient way to do this in EF Core that I don't know about.
I think this should work:
public IEnumerable<MyEntity> FindEntities(IEnumerable<MyEntityDtos> entries)
{
var props1=entries.Select(x=>x.Prop1).ToArray();
var props2=entries.Select(x=>x.Prop2).ToArray();
return dbContext.MyDbSet.Where(r => props1.Contains(r.Prop1) && props2.Contains(r.Prop2));
}
In the end, I've done this:
public static IEnumerable<MyEntity> GetRangeByKey(this DbSet<MyEntity> dbSet, IEnumerable<MyEntity> toFind)
{
var keys = new HashSet<string>(toFind.Select(e => e.Id));
IEnumerable<MyEntity> result = null;
for (int i = 0; i < keys.Length; i += 1000)
{
var keyChunk = keys[i..(Math.Min(i + 1000, keys.Length))];
var res = dbSet.Where(x => keyChunk.Any(k => x.ResourceArn == k));
if (result == null)
{
result = res;
}
else
{
result = result.Concat(res);
}
}
return result;
}
Basically I get the keys to find in a HashSet and use it to perform a Where query, which will be translated to a SQL IN clause which is quite fast. I do it in chunks because there's a maximum number of values you can put in a IN clause before the DB engine refuses it.

How to Cast a IQueryable/IEnumerable result to a custom Model C# EntityFramework

Lets say that I have a Repository with this function
public async Task<IEnumerable<Contacts>> GetAll()
{
return await _context.Contacts.ToListAsync();
}
Where the Contacts Entity is the same one returning the call. But I didn't want to use the same class because there's some fields that I like to keep out of the call. There's any way that I could "mirror" a second model called "ContactsModel" to return the data without using Anonymous calls like :
var result = context.t_validation.Where(a => a.isvalidated == 10).Select(x => new
{
x.date_released,
x.utoken,
x.Images,
x.images_key,
x.Type
});
Of putting into a loop and passing to this new Model :
foreach (var item in list)
{
decp.Add(new ValidationModel
{
uToken = item.utoken,
Date = item.date_released,
Images = bc.Decrypt(item.Images, item.images_key),
Type = item.Type
});
}
Thanks!
Because you are using custom method to decrypt an image, you will not be able to include it in the query, because EF will not be able to translate it into sql query.
Anonymous approach would be the best one
public async Task<IEnumerable<Contacts>> GetAll()
{
var models = await _context
.Contacts
.Select(contact => new
{
contact.date_released,
contact.utoken,
contact.Images,
contact.images_key,
contact.Type
})
.ToListAsync()
return models
.Select(item => new ValidationModel
{
uToken = item.utoken,
Date = item.date_released,
Images = bc.Decrypt(item.Images, item.images_key),
Type = item.Type
}
.ToList();
}
Of course you can wrap it with an extension methods, but if you are using this mapping only in one place you don't need to.

Why would C# linq to sql return the same exact record

So I have this Entity Framework query in which the SELECT statement which i can copy and run in sql server ctx.MainOrders returns 2 very different records.
However when i run this LINQ query with .AsEnumerable() and .Select(z => new MainOrder() i'm getting the EXACT SAME record twice! :/
This class is a POCO
public class MainOrder
Here is my query
public List<MainOrder> GetMainOrder(string hashString)
{
try
{
using (var ctx = new ClearContext())
{
var query = ctx.MainOrders
.Where(z => z.MainId == queryHashMain)
.AsEnumerable()
.Select(z => new MainOrder()
{
Email = z.Email,
AuthorizationFirstName = z.AuthorizationFirstName,
AuthorizationLastName = z.AuthorizationLastName,
Btn = z.Btn,
AccountNumber = z.AccountNumber,
UtilityTypeName = z.UtilityTypeName
}).ToList();
return query;
return new List<MainOrder>();
}
}
In your comments you mention a VIEW , that is the issue I bet.
the ctx.Mainorders query will show 2 records in sql server as it is a View in which MainId
Add in method AsNoTracking for view
var query = ctx.MainOrders.AsNoTracking()

C# Entity Framework filtering with .Where()

I am working in C# using Entity Framework and I am trying to filter a query of contacts to get all contact that have the same Id. I can get all Contacts, but I'm having issues filtering using Where. I know somethings wrong but I can't quite pinpoint it, any help would be appreciated.
See relevant code below:
public IEnumerable<model.Contact> Execute(GetContactById parameters)
{
IEnumerable<model.Contact> ContactsById = null;
DbRetryHandler.RetryHandler(delegate(DeviceModelContext retryContext)
{
ContactsById = retryContext.Contact
.Where(c => c.Id.equals(parameters.Id))
.Select(c => new model.Contact
{
// unrelated code
});
});
return ContactsById;
}
The provider has issues recognizing expressions it cannot translate to SQL. Try to simplify the expressions so that it can be translated to SQL more easily.
public IEnumerable<model.Contact> Execute(GetContactById parameters)
{
IEnumerable<model.Contact> ContactsById = null;
DbRetryHandler.RetryHandler(delegate(DeviceModelContext retryContext)
{
var parametersId = parameters.Id; // <-- store id in variable
camerasByDeviceId = retryContext.Contact
.Where(c => c.Id == parametersId) // <-- use == instead of Equals
.Select(c => new model.Camera
{
// unrelated code
});
});
return ContactsById;
}

Why is LINQ OrderByDescending not working with a view composed of a union between two tables?

I have a view in my SQL Server database that is a UNION ALL of two tables. When I retrieve all the rows from the view for a specific member, this is my call.
public IEnumerable<MemberTransaction> GetMemberTransactions(string socSecNo)
{
var query = Manager.MemberTransactions
.Where(m => m.SocSecNo == socSecNo)
.OrderByDescending(m => m.TranDate);
var results = query.Execute();
return results;
}
I call the Get method from my code and assign the returned collection to the datasource propery of a grid. The rows are not displayed as per the order by statement in the Get method. they are displayed in random order.
I am forced to do this to get the rows to display properly.
IEnumerable<MemberTransaction> transactions = FetchMemberTransactions(currentMember.SocSecNo);
MemberTransactionBS.DataSource = transactions.OrderByDescending(t => t.TranDate);
MemberTransactionsGrid.Refresh();
public IEnumerable<MemberTransaction> FetchMemberTransactions(string socSecNo)
{
var transactions = Repository.GetMemberTransactions(socSecNo);
return transactions;
}
Is there an issue with returning rows from a union? Why is the OrderByDescending not working as expected?
If the order is being returned correctly from the database (test this first like other answers sugest) try returning an IOrderedEnumerable<MemberTransaction> instead of IEnumerable<MemberTransaction>.
You said First Way doesn't work but it worked on me! So try Second Way please.
// First Way
public List<MemberTransaction> GetMemberTransactions(string socSecNo)
{
var orderedListOfData = Manager.MemberTransactions
.Where(m => m.SocSecNo == socSecNo)
.OrderByDescending(m => m.TranDate).ToList();
return orderedListOfData;
}
// Second Way
public List<MemberTransaction> GetMemberTransactions(string socSecNo)
{
var orderedListOfData = (from m in Manager.MemberTransactions
where m.SocSecNo == socSecNo
orderby m.TranDate descending
select m).ToList();
return orderedListOfData;
}

Categories