I'm using a homebrewed repository pattern (!) together with PetaPoco in my latest project. And when coding some data retrieval routines my brain suddenly made a jump.
Currently i have Repo.GetMyObjects that returns an IList<MyObject> from the db, and a Repo.GetMyObject that returns a MyObject.
Is this the correct way to go ahead? Or should I have my Repo.GetMyObjects return an IEnumerable<MyObject> and then use Repo.GetMyObjects().SingleOrDefault( q => q.ID == MyWantedObjectID) in my controller to get a single object?
To go even further than Ankur's answer: the way you are doing is actually more correct, because having to add SingleOrDefault() calls would seem to be something the repository should be doing for you.
Let your Repo.GetMyObject bet there and make it do what you have described. So that in future if required you can change the implementation and all the callers won't need any change.
It would be stupid to retrieve a whole collection of MyObject instances, if you only need one. Consider the performance-cost that this gives you, if you have thousands of instances in your database.
So, you'll need a GetMyObject method in your repository, which retrieves the only object you're interested in.
Related
I've looked through the source and I'm not finding anything (although I'm not great at IL), but I would like see if there is a way to provide Dapper a class instance instead of it always instantiating a new one. The reason for this is we may sometimes make two separate calls to two different stored procedures - one returns some columns of an 'entity', the other returns other columns. However, instead of the second query using the entity we received in the first call, we instead get two instances of essentially the same entity. It would be much more preferable for Dapper to use the existing entity class and map the query results to that existing class.
Is there any way to intercept Dapper's class instantiation so as to provide it with an existing instance if needed?
Excellent question. At the moment, it allows you to indicate a particular constructor, but it always news:
il.Emit(OpCodes.Newobj, specializedConstructor);
What we could do is make it possible to specify either a constructor or a static factory method; I suspect this would be just a three-line change to the core materializer code, plus a few other places. Not impossible, but then it gets into questions like calling-context: how does dapper provide caller-specified context to the factory. Again: all possible (protobuf-net does pretty much the same thing).
But none of that exists today. It wouldn't be impossible.
These linq queries can be written in both the ways. But choosing which way seems really to be confusing task. Please explain the difference in performance (if any) of these commands.
from table1Details in objDataContext.Table1s where table1Details.SomeId == 15
select new {....};
from table1Details in objDataContect.GetTable<Table1>() where table1Details.SomeId==15
select new {...};
That's not a difference related to LINQ at all. The data context is providing a property Table1s, which, internally, is just going to call GetTable<Table1>(). It's a convenience method with virtually no performance cost and absolutely no functional difference.
DataContext.GetTable Method
This method is the main entry point for querying. When a strongly
typed DataContext is created, new generated properties encapsulate
calls to this method. For example, a Customers property is
generated that returns GetTable<Customer>.
So for your case, there is no difference. Your DataContext has a property Table1, when you directly access it using objDataContext.Table1s it calls objDataContext.GetTable<Table1>()
But choosing which way seems really to be confusing task.
Why? What is confusing about it? Don't both ways work? Did you read the manual?
This method is the main entry point for querying. When a strongly typed DataContext is created, new generated properties encapsulate calls to this method. For example, a Customers property is generated that returns GetTable<Customer>.
GetTable<T>() just provides a generic way to access datasets, with runtime lookup (GetTable<UnknownEntityType>() will throw), as opposed to the generated, compile-time checked properties.
I want a method where I can call, that would query the database for my given query string. Which can be refferenced from different controllers/actions. (note, complexity of actual query is quite big).
So a few questions:
Where would the code go. A new controller? Helper?
How would I reference it (call it)?
What object, if following my current style, would be the return type.
public Something WebCostCentres()
{
using (var db = Database.OpenConnectionString(Mynamespace.Properties.Settings.Default.dbConnString,
"System.Data.SqlClient"))
{
//ViewBag.CostCentres = db.Query("SELECT DISTINCT CostCentreNo");
return db.Query("SELECT DISTINCT CostCentreNo");
}
}
I would create some kind of Service class for this.
You crate the service and call the method.
The same type as your Query method. IEnumerable<Something> would be an option. You might have to call ToList or ToArray to execute the query, because the connection might be closed.
The service layer is often called repository. Google for this and you will find tons of examples.
1.Where would the code go. A new controller? Helper?
A class. Service oriented architecure wise.
2.How would I reference it (call it)?
As local variable in the page, filled via your trusted IOC container.
3.What object, if following my current style, would be the return type
None. Our current style is outdated. Ever heard of LINQ? The IQueryable extensions to .NET? It is not like they are new. It should return either IEnumerable or IQueryable, and be in general generic. Or a specific type in case only one number is returned.
repository pattern is applicable too
See an example
http://mstecharchitect.blogspot.com/2009/08/aspnet-mvc-and-linq-to-sql-using.html
How would you do this (pseudo code): product1.Orders.AddRange(product2.Orders);
However, the function "AddRange" does not exist, so how would you copy all items in the EntityCollection "Orders" from product2 to product1?
Should be simple, but it is not...
The problem is deeper than you think.
Your foreach attempt fails, because when you call product1.Orders.Add, the entity gets removed from product2.Orders, thus rendering the existing enumerator invalid, which causes the exception you see.
So why does entity get removed from produc2? Well, seems quite simple: because Order can only belong to one product at a time. The Entity Framework takes care of data integrity by enforcing rules like this.
If I understand correctly, your aim here is to actually copy the orders from one product to another, am I correct?
If so, then you have to explicitly create a copy of each order inside your foreach loop, and then add that copy to product1.
For some reason that is rather obscure to me, there is no automated way to create a copy of an entity. Therefore, you pretty much have to manually copy all Order's properties, one by one. You can make the code look somewhat more neat by incorporating this logic into the Order class itself - create a method named Clone() that would copy all properties. Be sure, though, not to copy the "owner product reference" property, because your whole point is to give it another owner product, isn't it?
Anyway, do not hesitate to ask more questions if something is unclear. And good luck.
Fyodor
Based on the previous two answers, I came up with the following working solution:
public static void AddRange<T>(this EntityCollection<T> destinationEntityCollection,
EntityCollection<T> sourceEntityCollection) where T : class
{
var array = new T[sourceEntityCollection.Count()];
sourceEntityCollection.CopyTo(array,0);
foreach (var entity in array)
{
destinationEntityCollection.Add(entity);
}
}
Yes, the usual collection related functions are not there.
But,
1. Did you check CopyTo method?
2. Do you find any problem with using the iterator? You know, GetEnumerator, go through the collection and copy the entities?
The above two can solve your problems. But, I'm sure in .NET 3.0+ there would be compact solutions.
My answers are related to .NET 2.0
Ok, understand that I come from Cold Fusion so I tend to think of things in a CF sort of way, and C# and CF are as different as can be in general approach.
So the problem is: I want to pull a "table" (thats how I think of it) of data from a SQL database via LINQ and then I want to do some computations on it in memory. This "table" contains 6 or 7 values of a couple different types.
Right now, my solution is that I do the LINQ query using a Generic List of a custom Type. So my example is the RelevanceTable. I pull some data out that I want to do some evaluation of the data, which first start with .Contains. It appears that .Contains wants to act on the whole list or nothing. So I can use it if I have List<string>, but if I have List<ReferenceTableEntry> where ReferenceTableEntry is my custom type, I would need to override the IEquatable and tell the compiler what exactly "Equals" means.
While this doesn't seem unreasonable, it does seem like a long way to go for a simple problem so I have this sneaking suspicion that my approach is flawed from the get go.
If I want to use LINQ and .Contains, is overriding the Interface the only way? It seems like if there way just a way to say which field to operate on. Is there another collection type besides LIST that maybe has this ability. I have started using List a lot for this and while I have looked and looked, a see some other but not necessarily superior approaches.
I'm not looking for some fine point of performance or compactness or readability, just wondering if I am using a Phillips head screwdriver in a Hex screw. If my approach is a "decent" one, but not the best of course I'd like to know a better, but just knowing that its in the ballpark would give me little "Yeah! I'm not stupid!" and I would finish at least what I am doing completely before switch to another method.
Hope I explained that well enough. Thanks for you help.
What exactly is it you want to do with the table? It isn't clear. However, the standard LINQ (-to-Objects) methods will be available on any typed collection (including List<T>), allowing any range of Where, First, Any, All, etc.
So: what is you are trying to do? If you had the table, what value(s) do you want?
As a guess (based on the Contains stuff) - do you just want:
bool x= table.Any(x=>x.Foo == foo); // or someObj.Foo
?
There are overloads for some of the methods in the List class that takes a delegate (optionally in the form of a lambda expression), that you can use to specify what field to look for.
For example, to look for the item where the Id property is 42:
ReferenceTableEntry found = theList.Find(r => r.Id == 42);
The found variable will have a reference to the first item that matches, or null if no item matched.
There are also some LINQ extensions that takes a delegate or an expression. This will do the same as the Find method:
ReferenceTableEntry found = theList.FirstOrDefault(r => r.Id == 42);
Ok, so if I'm reading this correctly you want to use the contains method. When using this with collections of objects (such as ReferenceTableEntry) you need to be careful because what you're saying is you're checking to see if the collection contains an object that IS the same as the object you're comparing against.
If you use the .Find() or .FindAll() method you can specify the criteria that you want to match on using an anonymous method.
So for example if you want to find all ReferenceTableEntry records in your list that have an Id greater than 1 you could do something like this
List<ReferenceTableEntry> listToSearch = //populate list here
var matches = listToSearch.FindAll(x => x.Id > 1);
matches will be a list of ReferenceTableEntry records that have an ID greater than 1.
having said all that, it's not completely clear that this is what you're trying to do.
Here is the LINQ query involved that creates the object I am talking about, and the problem line is:
.Where (searchWord => queryTerms.Contains(searchWord.Word))
List<queryTerm> queryTerms = MakeQueryTermList();
public static List<RelevanceTableEntry> CreateRelevanceTable(List<queryTerm> queryTerms)
{
SearchDataContext myContext = new SearchDataContext();
var productRelevance = (from pwords in myContext.SearchWordOccuranceProducts
where (myContext.SearchUniqueWords
.Where (searchWord => queryTerms.Contains(searchWord.Word))
.Select (searchWord => searchWord.Id)).Contains(pwords.WordId)
orderby pwords.WordId
select new {pwords.WordId, pwords.Weight, pwords.Position, pwords.ProductId});
}
This query returns a list of WordId's that match the submitted search string (when it was List and it was just the word, that works fine, because as an answerer mentioned before, they were the same type of objects). My custom type here is queryTerms, a List that contains WordId, ProductId, Position, and Weight. From there I go about calculating the relevance by doing various operations on the created object. Sum "Weight" by product, use position matches to bump up Weights, etc. My point for keeping this separate was that the rules for doing those operations will change, but the basic factors involved will not. I would have even rather it be MORE separate (I'm still learning, I don't want to get fancy) but the rules for local and interpreted LINQ queries seems to trip me up when I do.
Since CF has supported queries of queries forever, that's how I tend to lean. Pull the data you need from the db, then do your operations (which includes queries with Aggregate functions) on the in-memory table.
I hope that makes it more clear.