IEnumerable<IGrouping<StatusType, Request>> group = requests.GroupBy(r=> r.StatusType );
The grouping function above works with when requests (List<Requests>) is from EntityFramework/db.
When changing the assignment of requests from db direct, to a web service,
the grouping isn't working as intended.
Digging a bit, I found that the hash or equality of the StatusType's is different when coming from db vs web (found out thru this post).
From the accepted answer of the post, I can bypass/(resolve?) the problem by overriding..
public class StatusType : IEquatable<int>
{ // omitted other crucial equality comparison components.
// but for brevity..
public override int GetHashCode()
{
return Id;
}
}
Although overriding StatusType somewhat resolves the issue,
I feel its quite risky as
I am not the author of the code base.
There are multiple references to StatusType increasing the potential
of impending failure.
My question,
Is there a way to group by the StatusTypeId (int)
requests.groupBy(r=> r.StatusTypeId) // returns IEnumerable<IGrouping<int,Rquest>>
but get the StatusType?
IEnumerable<IGrouping<StatusType,Rquest>>
Define comparer for StatusType:
public class StatusTypeComparer : IEqualityComparer<StatusType>
{
public bool Equals(StatusType x, StatusType y)
{
return x.Id == y.Id;
}
public int GetHashCode(StatusType obj)
{
return obj.Id.GetHashCode();
}
}
Pass it to GroupBy method:
IEnumerable<IGrouping<StatusType, Request>> group =
requests.GroupBy(r => r.StatusType,
new StatusTypeComparer());
Disclaimer: Backs has a much better answer than mine but I thought I'd post it anyway in the interests of diversity.
You might be able to get something like the functionality you're looking for by using multiple Linq queries. I don't know if there is an accessible implementation of IGrouping I can use, so I've gone with Tuple<StatusType, List<Request>> instead. It should have a similar effect. So, from your original query:
IEnumerable<IGrouping<int, Request>> group = requests.GroupBy(r=> r.StatusTypeId );
You can add the following line:
IEnumerable<Tuple<StatusType, List<Request>>> groupByStatusType =
group.Select(x => new Tuple<StatusType, List<Request>>(x.First().StatusType,
x.ToList()));
Or, you can do it all on one line:
IEnumerable<Tuple<StatusType, List<Request>>> group =
requests.GroupBy(r => r.StatusTypeId)
.Select(x => new Tuple<StatusType, List<Request>>(x.First().StatusType,
x.ToList()));
You can of course tweak the queries depending on what kind of output you're expecting, but this should at least get you started. Alternately, you could get a similar result by implementing a function that iterates through everything and "manually" creates an output.
Related
I've seen plenty of examples of how to use generic Objects in C#, but can I have a generic property for a static object?
I have 2 distinct lists of Providers:
List<Providers> OldProviders
List<Providers> NewProviders
OldProviders has providers from the database, and NewProviders has providers the user has selected in the View. If any OldProviders aren't in NewProviders, I want to remove them from the database. If any NewProviders aren't in OldProviders, I want to add them to the database. Simple.
One problem:
Provider has 2 properties that correspond to foreign keys important for comparison: StaffID and LicenseID (both integers)
Depending on the choice the user makes, I only care about one of these IDs.
Currently I have 2 sets of helper methods which are completely identical (6 total helpers), except for whether they compare using StaffID or LicenseID. It technically works, but I don't want to maintain it.
Here's an example:
private bool DeleteOldStaffProviders(List<Provider> oldSelectedStaff, List<Provider> newSelectedStaff)
{
foreach (var oldSelected in oldSelectedStaff)
{
bool remove = newSelectedStaff.SingleOrDefault(n => n.StaffID == oldSelected.StaffID) == null;
if (remove)
{
//<remove from database, return false if failure>
}
}
return true;
}
Is there a way I can rewrite this method with a generic parameter reference?
i.e.
newSelectedStaff.SingleOrDefault(n => n.T == oldSelected.T)
where T is either LicenseID or StaffID.
I've seen a lot of examples of people using LINQ and reflection for things kinda similar to this, but I can't seem to figure it out. If you could baby me through it, that would be appreciated.
Yes, use another parameter of type Func<Provider,int> to act as the selector:
private bool DeleteOldStaffProviders(List<Provider> oldSelectedStaff, List<Provider> newSelectedStaff, Func<Provider,Provider,bool> selector)
{
foreach (var oldSelected in oldSelectedStaff)
{
bool remove = newSelectedStaff.SingleOrDefault(n => selector(n) == selector(oldSelected)) == null;
if (remove)
{
//<remove from database, return false if failure>
}
}
return true;
}
usage
DeleteOldStaffProviders(oldStaff, newStaff, x => x.StaffID);
DeleteOldStaffProviders(oldStaff, newStaff, x => x.LicenseID);
You could do it another way - but I think its more clunky. Pass in a Func<Provider,Provider,bool> like this:
DeleteOldStaffProviders(oldStaff, newStaff, (o,n) => o.StaffID == n.StaffID);
And change a line to:
bool remove = newSelectedStaff.SingleOrDefault(n => selector(n,oldSelected))
Sorry if the title is misleading, wasn't sure how to describe this one.
My end goal is to have an extension method of IQueryable<T> and some form (see below for example) of expression that will allow me to have to return an IQueryable<EntityIndex<T>> (or similar) which contains the original T in the Entity field, and an array/ienumerable containing the elements as describe by the some form of expression.
I know that doesn't really make sense, hopefully it will after an example...
This is what I have so far:
class EntityIndex<T, TKey>
{
T Entity { get; set; }
// Doesn't have to be IEnumerable, whatever is easier
IEnuermable<TKey> Index { get; set; }
}
static class Elsewhere
{
[Extension()]
public IQueryable<EntityIndex<T, TKey>> IndexBy<T, TKey>(this IQueryable<T> source, Expression<Func<T, TKey[]>> indexSelector)
{
return source.Select(n => new EntityIndex<T, TKey> {
Entity = n,
Index = new T[] { n }.Select(indexSelector)
});
}
}
Note: The above does not compile, it's simply there to try and show what I'm trying to achieve.
I've used the standard selector, but sub-optimally, had to arbitrarily create an array of T on the assignment to the 'Index' property to be able to apply the selector. I'm hoping a better choice of parameter may resolve this, but possibly not. The main issue is this doesn't compile so if there is a minor tweak that will allow it to work that's fine by me, if you can understand my gibberish and understand what I'm trying to do, and happen to know a better way to go about it I'd be greatly appreciative.
Ideally, I need the solution to be understood by the L2S engine, which I'm not convinced the above is thanks to the introduction of the EntityIndex class, but I'm holding out hope that it'll treat it as an anonymous class.
EDIT:
Good point Damien, the bigger picture is probably much easier to describe...
I want an extension method that accepts an expression, the expression should describe which fields on the entity to index, which will be used after this particular expression to allow a criterion (where clause) to be applied to the selected fields.
Long story short, in a number of places in code we have a wildcard string search. If I have an EntityA with Property1, Property2, Property3, etc, it is not uncommon to see code such as:
Handwritten, please excuse minor typos
public string[] WildcardSearch(string prefixText, int count)
{
string searchTerm = prefixText.Replace(wildcard, string.Empty);
if (prefixText.StartsWith(wildcard) && prefixText.EndsWith(wildcard)) {
return entitySet.Where(n => n.Property1.Contains(searchTerm) || n.Property2.Contains(searchTerm)).Select(n => n.Property3).ToArray();
} else if (prefixText.StartsWith(wildcard)) {
return entitySet.Where(n => n.Property1.EndsWith(searchTerm) || n.Property2.EndsWith(searchTerm)).Select(n => n.Property3).ToArray();
// you get the picture, same with EndsWith, no wildcards defaults to contains...
}
}
EDIT:
Further clarification - using the above WildcardEarch as an example, what I was hoping for was to be able to have a selector as follows or similar:
Func<EntityA, IEnumerable<string>> indexSelector = n => new string[] {
n.Property1,
n.Property2
};
// Alternatively, a ParamArray of keySelector might work?
Func<EntityA, string>[] keySelectors = new Func<EntityA, string>[] {
n => n.Property1,
n => n.Property2
};
Given an adequate expression describing which fields on the entity to search, returning the IQueryable<EntitySearch<T>> as shown above, I hoped to be able to apply a single criterion, similar to:
Func<EntitySearch<T>, bool> criterion = n => false;
if (wildcardIsContains) {
criterion = n => n.Values.Any(x => x.Contains(searchTerm));
} else if (wildCardIsStartsWith) {
criterion = n => n.Values.Any(x => x.Contains(searchTerm));
//etc
}
Given the extension at the very top that I can't get to work, and this criterion logic, I should be able to take an IQueryable<T>, select some fields, and apply an appropriate wildcard search on the fields, finally returning IQueryable<T> again having added the filtering.
ThanksĀ¬!
Please comment if you need more information/clarification...
EDIT:
Fair one #subkamren and thanks for the interest. Some non-generic examples may be of use. I'll draft something up and add them shortly. For the time being, some clarification based on your comment...
Given an IQueryable<Animal> I want an extension allowing me to select fields on Animal which I intend to search/index by. For example, Animal.Description, Animal.Species.Name etc. This extension should return something like an IIndexedQueryable<Animal>. That is the issue I'm trying to deal with in the question above. The wider picture mentioned, which I'd be exceptionally pleased if you're willing to help with, is as follows:
The IIndexedQueryable<T> interface in turn I would like an extension for which could take a string search term. The extension should resolve the wildcards within the search term, extend the original IQueryable with the necessary criterion to perform a search on the indexed fields, and return an IQueryable<T> again.
I appreciate this could be done in a single step, but I hoped to do it this way so that later on I can look into adding a third extension method applicable to IIndexedQueryable<T> allowing me to perform a freetext search with SQL Server... ^^ Make any sense?
That's the bigger picture at least, this question deals primarily with being able to specify the fields I aim to index in such a way I can use them thereafter as mentioned here.
So something like:
public static IEnumerable<EntityIndex<T, Y>> IndexBy<T, Y>(this IEnumerable<T> entities, Func<T, Y> indexSelector) {
return entities.Select(e => new EntityIndex<T, Y> { Entity = e, IndexValue = indexSelector(e) });
}
Noting that generically defining EntityIndex with the TIndexType (called Y here) is important because you don't know ahead of time what the index is. The use of a generic allows Y to be an enumeration, thus the following would work as an index selector:
// Assuming Animal has attributes "Kingdom", "Phylum", "Family", "Genus", "Species"
// this returns an enumeration of EntityIndex<Animal, String[]>
var animalsClassified = someAnimals.IndexBy(a => new String[] { a.Kingdom, a.Phylum, a.Family, a.Genus, a.Species });
EDIT (Adding further detail):
Using the above, you can group the results by unique index value:
var animalClassifications = animalsClassified
.SelectMany(ac => ac.IndexValue.Select(iv => new { IndexValue = iv, Entity = ac.Entity }))
.GroupBy(kvp => kvp.IndexValue)
What I've described here, by the way, is (a very simplified form of) the MapReduce algorithm as popularized by Google. A distributed form of the same is commonly used for keyword identification in text search, where you want to build an index of (search term)->(list of containing documents).
I have a simple issue with Entity Framework syntax for the "not in" SQL equivalent. Essentially, I want to convert the following SQL syntax into Entity Framework syntax:
select ID
from dbo.List
where ID not in (list of IDs)
Here is a method that I use for looking up a single record:
public static List GetLists(int id)
{
using (dbInstance db = new dbInstance())
{
return db.Lists.Where(m => m.ID == id);
}
}
Here is a pseudo-method that I want to use for this:
public static List<List> GetLists(List<int> listIDs)
{
using (dbInstance db = new dbInstance())
{
return db.Lists.Where(**** What Goes Here ****).ToList();
}
}
Can anyone give me pointers as to what goes in the Where clause area? I read some forums about this and saw mention of using .Contains() or .Any(), but none of the examples were a close enough fit.
Give this a go...
public static List<List> GetLists(List<int> listIDs)
{
using (dbInstance db = new dbInstance())
{
// Use this one to return List where IS NOT IN the provided listIDs
return db.Lists.Where(x => !listIDs.Contains(x.ID)).ToList();
// Or use this one to return List where IS IN the provided listIDs
return db.Lists.Where(x => listIDs.Contains(x.ID)).ToList();
}
}
These will turn into approximately the following database queries:
SELECT [Extent1].*
FROM [dbo].[List] AS [Extent1]
WHERE NOT ([Extent1].[ID] IN (<your,list,of,ids>))
or
SELECT [Extent1].*
FROM [dbo].[List] AS [Extent1]
WHERE [Extent1].[ID] IN (<your,list,of,ids>)
respectively.
This one requires you to think backwards a little bit. Instead of asking if the value is not in some list of ids, you have to ask of some list of id's does not contain the value. Like this
int[] list = new int[] {1,2,3}
Result = (from x in dbo.List where list.Contains(x.id) == false select x);
Try this for starters ...
m => !listIDs.Contains(m.ID)
This might be a way to do what you want:
// From the method you provided, with changes...
public static List GetLists(int[] ids) // Could be List<int> or other =)
{
using (dbInstance db = new dbInstance())
{
return db.Lists.Where(m => !ids.Contains(m.ID));
}
}
However I've found that doing so might raise error on some scenarios, specially when the list is too big and connection is somewhat slow.
Remember to check everything else BEFORE so this filter might have less values to check.
Also remember that Linq does not populate the variable when you build your filter/query (at least not by default). If you're going to iterate for each record, remember to call a ToList() or ToArray() method before, unless each record has 500MB or more...
I have a series of about 30 lookup tables in my database schema, all with the same layout (and I would prefer to keep them as separate tables rather than one lookup table), and thus my Linq2SQL context has 30 entities for these lookup tables.
I have a standard class that I would use for CRUD operations on each of these 30 entites, for example:
public class ExampleAttributes : IAttributeList
{
#region IAttributeList Members
public bool AddItem(string Item, int SortOrder)
{
MyDataContext context = ContextHelper.GetContext();
ExampleAttribute a = new ExampleAttribute();
a.Name = Item;
a.SortOrder = SortOrder;
context.ExampleAttributes.InsertOnSubmit(a);
try
{
context.SubmitChanges();
return true;
}
catch
{
return false;
}
}
public bool DeleteItem(int Id)
{
MyDataContext context = ContextHelper.GetContext();
ExampleAttribute a = (from m in context.ExampleAttributes
where m.Id == Id
select m).FirstOrDefault();
if (a == null)
return true;
// Make sure nothing is using it
int Count = (from m in context.Businesses
where m.ExampleAttributeId == a.Id
select m).Count();
if (Count > 0)
return false;
// Delete the item
context.ExampleAttributes.DeleteOnSubmit(a);
try
{
context.SubmitChanges();
return true;
}
catch
{
return false;
}
}
public bool UpdateItem(int Id, string Item, int SortOrder)
{
MyDataContext context = ContextHelper.GetContext();
ExampleAttribute a = (from m in context.ExampleAttributes
where m.Id == Id
select m).FirstOrDefault();
a.Name = Item;
a.SortOrder = SortOrder;
try
{
context.SubmitChanges();
return true;
}
catch
{
return false;
}
}
public String GetItem(int Id)
{
MyDataContext context = ContextHelper.GetContext();
var Attribute = (from a in context.ExampleAttributes
where a.Id == Id
select a).FirstOrDefault();
return Attribute.Name;
}
public Dictionary<int, string> GetItems()
{
Dictionary<int, string> Attributes = new Dictionary<int, string>();
MyDataContext context = ContextHelper.GetContext();
context.ObjectTrackingEnabled = false;
Attributes = (from o in context.ExampleAttributes orderby o.Name select new { o.Id, o.Name }).AsEnumerable().ToDictionary(k => k.Id, v => v.Name);
return Attributes;
}
#endregion
}
I could replicate this class 30 times with very minor changes for each lookup entity, but that seems messy somehow - so can this class be genericised so I can also pass it the type I want, and have it handle internally the type differences in the linq queries? That way, I have one class to make additions to, one class to bug fix et al - seems the way that it should be done.
UPDATE:
Andrews answer below gave me the option that I was really looking at while thinking about the question (passing the type in) but I need more clarification on how to genericise the linq queries. Can anyone clarify this?
Cheers
Moo
There are a couple things you can try.
One is to define an interface that has all the relevant fields that the thirty entity classes share. Then, you would be able to have each entity class implement this interface (let's call it IMyEntity) by doing something like
public partial class EntityNumber1 : IMyEntity
{
}
for each entity (where EntityNumber1 is the name of one of the entity classes). Granted, this is still thirty different definitions, but your CRUD operation class could then operate on IMyEntity instead of having to write a new class each time.
A second way to do this is simply to genericize the CRUD operation class, as you suggest:
public class ExampleAttributes<T> : IAttributeList
{
...
which allows you to use T as the type on which to operate. Granted, this might be easier in combination with the first method, since you would still have to check for the presence of the attributes and cast the entity to the appropriate type or interface.
Edit:
To check for the presence of the appropriate properties on the entity, you might need to use reflection methods. One way to check whether the given type T has a particular property might be to check for
typeof(T).GetProperties().OfType<PropertyInfo>().Count<PropertyInfo>(pi => pi.Name == "MyPropertyName" && pi.GetGetMethod().ReturnType == typeof(TypeIWant)) > 0
Of course, replace TypeIWant with the type you are expecting the property to be, and replace MyPropertyName with the name of the property for which you are checking.
Add a parameter to the constructors which specifies the type. Then you can work with it internally. One class, with perhaps a switch statement in the constructor.
For genericising a LINQ query, the biggest problem is that your DataContext has the collections based on type. There are a few ways this can be circumvented. You could try to access it using reflection, but that will require quite a bit of hacking and would pretty much destroy all efficiency that LINQ to SQL would provide.
The easiest way seems to be to use Dynamic LINQ. I have not used it personally, but it seems like it should support it. You can find more information in this thread: Generic LINQ query predicate?
and on http://aspalliance.com/1569_Dynamic_LINQ_Part_1_Using_the_LINQ_Dynamic_Query_Library.1
Maybe someone else can provide more information about this?
This isn't necessarily an answer to the question, but may be a solution to your problem. Have you considered generating all the classes that you need? T4 is built into Visual Studio, and can generate code for you. The link below describes it fairly broadly, but contains heaps of links for further information.
http://www.hanselman.com/blog/T4TextTemplateTransformationToolkitCodeGenerationBestKeptVisualStudioSecret.aspx
That way, you can define all the methods in one place, and generate the class files for your 30-odd lookup models. One place to make changes etc.
Maybe worth considering, and if not, still worth knowing about.
If I have a static method like this
private static bool TicArticleExists(string supplierIdent)
{
using (TicDatabaseEntities db = new TicDatabaseEntities())
{
if((from a in db.Articles where a.SupplierArticleID.Equals(supplierIdent) select a).Count() > 0)
return true;
}
return false;
}
and use this method in various places in foreach loops or just plain calling it numerous times, does it create and open new connection every time?
If so, how can I tackle this? Should I cache the results somewhere, like in this case, I would cache the entire Classifications table in Memory Cache? And then do queries vs this cached object?
Or should I make TicDatabaseEntities variable static and initialize it at class level?
Should my class be static if it contains only static methods? Because right now it is not..
Also I've noticed that if I return result.First() instead of FirstOrDefault() and the query does not find a match, it will issue an exception (with FirstOrDefault() there is no exception, it returns null).
Thank you for clarification.
new connections are non-expensive thanks to connection caching. Basically, it grabs an already open connection (I htink they are kept open for 2 minutes for reuse).
Still, caching may be better. I do really not like the "firstordefault". Thinks of whether you can acutally pull in more in ONE statement, then work from that.
For the rest, I can not say anything - too much depends on what you actually do there logically. What IS TicDatabaseEntities? CAN it be cached? How long? Same with (3) - we do not know because we do not know what else is in there.
If this is something like getting just some lookup strings for later use, I would say....
Build a key out of classI, class II, class III
load all classifications in (I assume there are only a couple of hundred)
Put them into a static / cached dictionary, assuming they normally do not change (and I htink I have that idea here - is this a financial tickstream database?)
Without business knowledge this can not be answered.
4: yes, that is as documented. First gives first or an exception, FirstOrDefault defaults to default (empty struct initialized with 0, null for classes).
Thanks Dan and TomTom, I've came up with this. Could you please comment this if you see anything out or the order?
public static IEnumerable<Article> TicArticles
{
get
{
ObjectCache cache = MemoryCache.Default;
if (cache["TicArticles"] == null)
{
CacheItemPolicy policy = new CacheItemPolicy();
using(TicDatabaseEntities db = new TicDatabaseEntities())
{
IEnumerable<Article> articles = (from a in db.Articles select a).ToList();
cache.Set("TicArticles", articles, policy);
}
}
return (IEnumerable<Article>)MemoryCache.Default["TicArticles"];
}
}
private static bool TicArticleExists(string supplierIdent)
{
if (TicArticles.Count(p => p.SupplierArticleID.Equals(supplierIdent)) > 0)
return true;
return false;
}
If this is ok, I'm going to make all my method follow this pattern.
does it create and open new connection every time?
No. Connections are cached.
Should I cache the results somewhere
No. Do not cache entire tables.
should I make TicDatabaseEntities variable static and initialize it at class level?
No. Do not retain a DataContext instance longer than a UnitOfWork.
Should my class be static if it contains only static methods?
Sure... doing so will prevent anyone from creating useless instances of the class.
Also I've noticed that if I return result.First() instead of FirstOrDefault() and the query does not find a match, it will issue an exception
That is the behavior of First. As such - I typically restrict use of First to IGroupings or to collections previously checked with .Any().
I'd rewrite your existing method as:
using (TicDatabaseEntities db = new TicDatabaseEntities())
{
bool result = db.Articles
.Any(a => a.supplierArticleID.Equals(supplierIdent));
return result;
}
If you are calling the method in a loop, I'd rewrite to:
private static Dictionary<string, bool> TicArticleExists
(List<string> supplierIdents)
{
using (TicDatabaseEntities db = new TicDatabaseEntities())
{
HashSet<string> queryResult = new HashSet(db.Articles
.Where(a => supplierIdents.Contains(a.supplierArticleID))
.Select(a => a.supplierArticleID));
Dictionary<string, bool> result = supplierIdents
.ToDictionary(s => s, s => queryResult.Contains(s));
return result;
}
}
I'm trying to find the article where I read this, but I think it's better to do (if you're just looking for a count):
from a in db.Articles where a.SupplierArticleID.Equals(supplierIdent) select 1
Also, use Any instead of Count > 0.
Will update when I can cite a source.