With Linqtosql, How to get a collection of Users based on an array of UserID's - asp.net-mvc

Using linqtosql, how would I get a colleciton of User objects, if I have an array of UserID's that I want to fetch?

You can use Contains to check if each UserID is in the array that you have.
int[] userIDs = ...
var users = db.Users.Where( u => userIDs.Contains( u.UserID ) );

If you want to avoid a SET operation and user chained ORs instead, you can use the PredicateBuilder to help you with that.
It goes something like this:
var userIDs = new[] { 1, 2, 3, 4, 5 };
// build multiple OR expressions
var filter = PredicateBuilder.False<User>();
foreach (var id in userIDs) {
filter = filter.Or(x => x.UserID == id);
}
// fetch data
using (var db = new TheDataContext()) {
var users = db.Users.Where(filter);
// wham! - we have users now.
}
Take a look at the blog post to understand how it works. This basically creates a long chaining ORs for each user id in the list before passing it to a WHERE clauses.

Try this:
using(var db=new MyDataContext())
{
var users=db.Users.Where(u=>userIds.Contains(u.Id));
}

Related

Shuffle the results of a LINQ query based on SessionID

I'm working on an ASP.NET MVC application with Entity Framework 6 and a SQL Server database.
I'm trying to shuffle the results of a query by adding a SortingCode which I'd like to assign a value based on the current SessionId, so that every time the returned rows are shuffled without affecting the pagination. SortingCode in this attempt is a string, but it can be any type, as long as it allows me to get shuffled results. I have something like this:
var sessionId = Session.SessionID.GetHashCode();
var rnd = new Random(sessionId);
var query = (from l in _context.Adverts
select new AdvertSummary
{
Id = l.Id,
Title = l.Title,
Description = l.Description,
SortingCode = l.Title.OrderBy(x => rnd.Next()).ToString(),
});
The IQueryable result is then converted into a list later on in my code with:
var pagedResults = query.Skip(skip).Take(pageSize).ToList();
The above attempt with the Random class doesn't work, and results in an error
DbExpressionBinding requires an input expression with a collection ResultType
Is there anything that I can do to get shuffled results?
I would suggest to use SqlFunctions.Checksum for such task. SortingCode will be nearly close to the seeded Random.
var sessionId = Session.SessionID;
var query =
from l in _context.Adverts
select new AdvertSummary
{
Id = l.Id,
Title = l.Title,
Description = l.Description,
SortingCode = SqlFunctions.Checksum(sessionId, l.Title)
};
var pagedResults = query
.OrderBy(x => x.SortingCode)
.ThenBy(x => x.Id)
.Skip(skip)
.Take(pageSize)
.ToList();

Selecting multiple from LINQ query

I use this little piece of code to get the IDs I need, and put them in an array
var userids = from a in db.Person
select a.idlist;
string[] idarray = userids.FirstOrDefault().ToString().Split(';');
How can I use this array of ids to select the matching rows in another query like this
[HttpGet]
public ActionResult GetStuff()
{
var Item = from a in db.Table
where a.id == idarray[0]
and where a.id == idarray[1]
and where a.id == idarray[2]
etc...
select new
{
a.itemid,
a.Element
};
return Json(Item, JsonRequestBehavior.AllowGet);
}
Try something like this:
var Item = from a in db.Table
where idarray.Contains(a.id)
select new
{
a.itemid,
a.Element
};
var Item = from a in db.Table
where idarray.Contains(a.id)
select new
{
a.itemid,
a.Element
}.ToArray();
Don't you want to use Extension Method Lambda syntax? I is same Linq, but just has more code-like view:
var Item = db.Table.Where(x => x.Contains(a.id))
.Select(x => new
{
a.itemid,
a.Element
}).ToArray();
Here's what I usually do.
Get the IDs you need:
var ids = something.Where(s => s.SomeCondition).Select(s => s.Id);
Now Lets get the data based on the Ids:
var response = anothertable.Where(a => ids.Contains(a.Id);
You then can make it a list, array, or whatever you want to do with it. It will go through all the records in anothertable and find the records where the a.Id matches any of the ids.

Search a collection of objects

I'm trying to search for a collection of potential nodes but unable to do it...
I have a product that has a relationship with many instances. I would like to query the DB and get all the instances that are in a list that i get from the user.
Cypher:
var query = _context
.Cypher
.Start(new
{
instance = startBitsList,
product = productNode.Reference,
})
.Match("(product)-[:HasInstanceRel]->(instance)")
.Return(instance => instance.Node<ProductInstance>());
The problem is startBitsList... I use StringBuilder to generate a query that contains all the instances I'm looking for:
private static string CreateStartBits(IEnumerable<string> instanceNames)
{
var sb = new StringBuilder();
sb.AppendFormat("node:'entity_Name_Index'(");
foreach (var id in productIds)
{
sb.AppendFormat("Name={0} OR ", id);
}
sb.Remove(sb.Length - 4, 4);
sb.Append(")");
var startBitsList = sb.ToString();
return startBitsList;
}
I get exceptions when trying to run this cypher...
Is there a better way to search for multiple items that are stored in the collection I get from the user?
OK, I think there are a couple of issues at play here, first I'm presuming you are using Neo4j 1.9 and not 2.0 - hence using the .Start.
Have you tried taking your query and running it in Neo4j? This should be your first port of call, typically it's easy to add a breakpoint on the .Results call and add a 'watch' for query.Query.DebugText.
However, I don't think you need to use the StartBits the way you are, I think you'd be better off filtering with a .Where as you already have the start point:
private static ICypherFluentQuery CreateWhereClause(ICypherFluentQuery query, ICollection<string> instanceNames)
{
query = query.Where((Instance instance) => instance.Name == instanceNames.First());
query = instanceNames.Skip(1).Aggregate(query, (current, localInstanceName) => current.OrWhere((Instance instance) => instance.Name == localInstanceName));
return query;
}
and your query becomes something like:
var prodReference = new NodeReference<Product>(2);
var query =
Client.Cypher
.ParserVersion(1, 9)
.Start(new {product = prodReference})
.Match("(product)-[:HasInstanceRel]->(instance)");
query = CreateWhereClause(query, new[] {"Inst2", "Inst1"});
var resultsQuery = query.Return(instance => instance.As<Node<Instance>>());
2 things of note
We're not using the indexes - there is no benefit to using them as you have the start point and traversing to the 'instances' is a simple process for Neo4j.
The 'CreateWhereClause' method will probably go wrong if you pass in an empty list :)
The nice thing about not using the indexes is that - because they are legacy - you are set up better for Neo4j 2.0

Client Side Query to filter by extended properties

I have a need where i want to get the count of deleted items and get change set/collection for items that are not deleted.
How can i achieve that ?
i am able to do it using the LINQJS, but was wondering if there is more proper way of doing it.
var countryType = manager.metadataStore.getEntityType("Country");
var countries = manager.getEntities(countryType);
var deletedCount = Enumerable.From(countries)
.Where(function (x) {
return x.entityAspect.entityState == "Deleted"
}).Count();
self.totalRows(self.totalServerRows() - deletedCount);
var queryResult = Enumerable.From(countries)
.OrderBy(function(x){ x.Country_Code })
.Where(function (x) {
return x.entityAspect.entityState != "Deleted"
})
.Skip(self.pageIndex() * self.pageSize())
.Take(self.pageSize())
.ToArray();
self.list(queryResult);
The EntityManager.getEntities call is overloaded (see: http://www.breezejs.com/sites/all/apidocs/classes/EntityManager.html#method_getEntities ) so that you can simply ask for those entities within the entityManager that are of specific types or in specified states. So for 'deleted, try this:
var deletedEntities = em.getEntities(null, [EntityState.Deleted]);
or if you wanted just the Added or Modified entities
var deletedEntities = em.getEntities(null, [EntityState.Added, EntityState.Modified]);
I hope this helps.

load navigation properties with filter for Entity Framework 4.3

Few days back I put a question regarding mapping two classes Message and MessageStatusHistory using EF. The mapping is going fine but I am facing some problems with the navigation property StatusHistory in class Message that relates it to MessageStatusHistory objects. I am loading the messages for one user only and want to the statuses pertaining to that user only. Like I would want to show if the user has marked message as read/not-read and when. If I use default loading mechanism like following it loads all the history related to the message irrespective of the user:
IDbSet<Message> dbs = _repo.DbSet;
dbs.Include("StatusHistory").Where(x=>x.MessageIdentifier == msgIdentifier);
To filter history for one user only I tried following trick:
IDbSet<Message> dbs = _repo.DbSet;
var q = from m in dbs.Include("StatusHistory")
where m.MessageIdentifier == msgIdentifier
select new Message
{
MessageIdentifier = m.MessageIdentifier,
/*OTHER PROPERTIES*/
StatusHistory = m.StatusHistory
.Where(x => x.UserId == userId).ToList()
};
return q.ToList();//THROWING ERROR ON THIS LINE
I am getting the error:
The entity or complex type 'MyLib.Biz.Message' cannot be constructed in a LINQ
to Entities query.
I have tried by commenting StatusHistory = m.StatusHistory.Where(x => x.UserId == userId).ToList() also but it has not helped.
Please help me in getting Messages with filtered StatusHistory.
EDIT:- above is resolved with this code:
var q = from m in _repository.DBSet.Include("Histories")
where m.MessageIdentifier == id
select new {
m.Id,/*OTHER PROPERTIES*/
Histories = m.Histories.Where(x =>
x.SenderId == userId).ToList()
};
var lst = q.ToList();
return lst.Select(m => new Message{
Id = m.Id, MessageIdentifier = m.MessageIdentifier,
MessageText = m.MessageText, Replies = m.Replies,
ReplyTo = m.ReplyTo, Histories = m.Histories, SenderId =
m.SenderId, SenderName = m.SenderName, CreatedOn = m.CreatedOn
}).ToList();
But if I try to include replies to the message with:
from m in _repository.DBSet.Include("Replies").Include("Histories")
I am getting error on converting query to List with q.ToList() for Histories = m.Histories.Where(x=> x.SenderId == userId).ToList().
About your EDIT part: You cannot use ToList() in a projection, just leave it an IEnumerable<T> and convert to a List<T> when you construct the Message. You also don't need to create two list objects, you can switch from the LINQ to Entities query to LINQ to Objects (the second Select) by using AsEnumerable():
var list = (from m in _repository.DBSet
where m.MessageIdentifier == id
select new {
// ...
Histories = m.Histories.Where(x => x.SenderId == userId)
})
.AsEnumerable() // database query is executed here
.Select(m => new Message {
// ...
Histories = m.Histories.ToList(),
// ...
}).ToList();
return list;
Be aware that Include has no effect when you use a projection with select. You need to make the properties that you want to include part of the projection - as you already did with select new { Histories.....

Resources