When using SubSonic, do you return the data as a dataset or do you put that in a strongly typed custom collection or a generic object?
I ran through the subsonic project and for the four stored procs I have in my DB, it gave me a Sps.cs with 4 methods which return a StoredProcedure object.
If you used a MVC, do you usually use the StoredProcedure object or wrap that around your business logic and return a dataset, list, collection or something else?
Are datasets still the norm or is that replaced by something else?
If the results of the stored procedure has the same schema as one of your tables, you can build a collection using this code (SubSonic 2.1):
ProductCollection coll = new ProductCollection();
coll.LoadAndCloseReader(SPs.GetProducts(1).GetReader());
ExecuteTypedList<> is your best friend in this case:
IList<Product> list=SPs.GetProducts().ExecuteTypedList<Product>();
If my stored procedure returns all the fields from one of the tables for which I have a SubSonic object then I do a LoadAndCloseReader on the result of the stored procedure. If my stored procedure returns data that does not match a SubSonic object then I just work with it as a dataset.
Perhaps return a datareader and then iterate it to populate some custom objects. Alternatively the quick and dirty way (since you're not using domain driven design) create a view in the DB with the same structure as the stored proc, then load the result into your ViewObjectCollection similar to John's code.
You can do data readers, but that's so 1999. Returning objects is a breeze with SubSonic, and easier to use than a data reader. You can retrieve objects like so:
Dim Charts As Generic.List(Of MusicDB.Billboard) = _
New SubSonic.Select(MusicDB.DB.Repository.Provider, New String() _
{"Prefix", "Artist", "Track", "ArtistNarrowToken", "TrackNarrowToken", "ArtistId", "TrackId", "TrackYear"}). _
From(MetadataTagger.MusicDB.Tables.Billboard). _
Where(MusicDB.Billboard.Columns.ArtistNarrowToken).IsLessThan(10). _
Or(MusicDB.Billboard.Columns.TrackId).IsNull(). _
OrderAsc(New String() {"TrackYear"}).ExecuteTypedList(Of MetadataTagger.MusicDB.Billboard)()
Related
I've pretty much looked everywhere I can, and I'm having a hard time trying to find the solution. it took me a week to create an immensely complex calculation query using a stored procedure, and I'd like to fetch the results from this query and place into a POCO class, similar to what I've done before using EF 6.
Map Stored Procedure Column names to POCO DTO
Basically this:
var p1 = new SqlParameter { ParameterName = "Param1", Value = 1 };
var p2 = new SqlParameter { ParameterName = "Param2", Value = 2 };
string query = "EXEC Calcs_Selections #Param1, #Param2";
var calcs = context.Database.SqlQuery<CalcViewPOCO>(query, p1, p2).ToList();
I've read literature found here:
EF Core Querying Raw SQL
Raw SQL Query without DbSet - Entity Framework Core
And discovered there is no more "free sql" in EF Core anymore. The FromSQL basically projects the results into a real entity found in the database, which I don't want because I don't have a table that has the same columns found. Instead, one solution is to extend the DBContext, and create a new DBSet
But I'm really not sure how to do this. I have a database first model, and used Scaffold-DbContext:
Getting Started with EF Core on ASP.NET Core with an Existing Database
I don't want to add to the context that was created automatically, in my case ProjectAContext, since if I make any more changes to the database, and run scaffolding again, it will overwrite my changes.
Though I couldn't wait any longer for the newer versions of EF Core to add functionality to what I asked, I found a library that helped me solve this solution.
https://github.com/snickler/EFCore-FluentStoredProcedure
It allowed me to take a result set, and map to a list of DTOs.
Sample shown on from the repo:
var dbContext = GetDbContext();
dbContext.LoadStoredProc("dbo.SomeSproc")
.WithSqlParam("fooId", 1)
.ExecuteStoredProc((handler) =>
{
var fooResults = handler.ReadToList<FooDto>();
// do something with your results.
});
Good day!
I've a legacy application where data access layer consists of classes where queries are done using SqlConnection/SqlCommand and results are passed to upper layers wrapped in untyped DataSets/DataTable.
Now I'm working on integrating this application into newer one where written in ASP.NET MVC 2 where LINQ2SQL is used for data access. I don't want to rewrite fancy logic of generating complex queries that are passed to SqlConnection/SqlCommand in LINQ2SQL (and don't have permission to do this), but I'd like to have result of these queries as strong-typed objects collection instead of untyped DataSets/DataTable.
The basic idea is to wrap old data access code in a nice-looking from ASP.NET MVC "Model".
What is the fast\easy way of doing this?
Additionally to the answer below here is a nice solution based on AutoMapper: http://elegantcode.com/2009/10/16/mapping-from-idatareaderidatarecord-with-automapper/
An approach that you could take is using the DataReader and transfer. So for every object you want to work with define the class in a data transfer object folder (or however your project is structured) then in you data access layer have something along the lines of the below.
We used something very similar to this in a project with a highly normalized database but in the code we did not need that normalization so we used procedures to put the data into more usable objects. If you need to be able to save these objects as well you will need handle translating the objects into database commands.
What is the fast\easy way of doing
this?
Depending on the number of classes etc this is could not be the fastest approach but it will allow you to use the objects very similarly to the Linq objects and depending on the type of collections used (IList, IEnumerable etc) you will be able to use the extension methods on those types of collections.
public IList<NewClass> LoadNewClasses(string abc)
{
List<NewClass> newClasses = new List<NewClass>();
using (DbCommand command = /* Get the command */)
{
// Add parameters
command.Parameters["#Abc"].Value = abc;
// Could also put the DataReader in a using block
IDataReader reader = /* Get Data Reader*/;
while (reader.Read())
{
NewClass newClass = new NewClass();
newClass.Id = (byte)reader["Id"];
newClass.Name = (string)reader["Name"];
newClasses.Add(newClass);
}
reader.Close();
}
return newClasses;
}
I'm building an app around Vici Coolstorage (asp.net version). I have my classes created and mapped to my database tables and can pull a list of all records fine.
I've written a stored procedure where the query jumps across databases that aren't mapped with Coolstorage, however, the fields in the query result map directly to one of my classes. The procedure takes 1 parameter.
so 2 questions here:
how do i execute the stored procedure? i'm doing this
CSParameterCollection collection = new CSParameterCollection();
collection.Add("#id", id);
var result = Vici.CoolStorage.CSDatabase.RunQuery("procedurename", collection);
and getting the exception "Incorrect syntax near 'procedurename'." (i'm guessing this is because it's trying to execute it as text rather than a procedure?)
and also, since the class representing my table is defined as abstract, how do i specify that result should create a list of MyTable objects instead of generic or dynamic or whatever objects? if i try
Vici.CoolStorage.CSDatabase.RunQuery<MyTable>(...)
the compiler yells at me for it being an abstract class.
There's a shortcut in CoolStorage to run a stored procedure. Simply prefix the stored procedure name with "!":
CSDatabase.RunQuery("!procedurename", collection);
I've got a repository using LINQ for modelling the data that has a whole bunch of functions for getting data out. A very common way of getting data out is for things such as drop down lists. These drop down lists can vary. If we're creating something we usually have a drop down list with all entries of a certain type, which means I need a function available which filters by the type of entity. We also have pages to filter data, the drop down lists only contain entries that currently are used, so I need a filter that requires used entries. This means there are six different queries to get the same type of data out.
The problem with defining a function for each of these is that there'd be six functions at least for every type of output, all in one repository. It gets very large, very quick. Here's something like I was planning to do:
public IEnumerable<Supplier> ListSuppliers(bool areInUse, bool includeAllOption, int contractTypeID)
{
if (areInUse && includeAllOption)
{
}
else if (areInUse)
{
}
else if (includeAllOption)
{
}
}
Although "areInUse" doesn't seem very English friendly, I'm not brilliant with naming. As you can see, logic resides in my data access layer (repository) which isn't friendly. I could define separate functions but as I say, it grows quite quick.
Could anyone recommend a good solution?
NOTE: I use LINQ for entities only, I don't use it to query. Please don't ask, it's a constraint on the system not specified by me. If I had the choice, I'd use LINQ, but I don't unfortunately.
Have your method take a Func<Supplier,bool> which can be used in Where clause so that you can pass it in any type of filter than you would like to construct. You can use a PredicateBuilder to construct arbitrarily complex functions based on boolean operations.
public IEnumerable<Supplier> ListSuppliers( Func<Supplier,bool> filter )
{
return this.DataContext.Suppliers.Where( filter );
}
var filter = PredicateBuilder.False<Supplier>();
filter = filter.Or( s => s.IsInUse ).Or( s => s.ContractTypeID == 3 );
var suppliers = repository.ListSuppliers( filter );
You can implement
IEnumerable<Supplier> GetAllSuppliers() { ... }
end then use LINQ on the returned collection. This will retrieve all suppliers from the database that are then filtered using LINQ.
Assuming you are using LINQ to SQL you can also implement
IQueryable<Supplier> GetAllSuppliers() { ... }
end then use LINQ on the returned collection. This will only retrieve the necessary suppliers from the database when the collection is enumerated. This is very powerful and there are also some limits to the LINQ you can use. However, the biggest problem is that you are able to drill right through your data-access layer and into the database using LINQ.
A query like
var query = from supplier in repository.GetAllSuppliers()
where suppliers.Name.StartsWith("Foo") select supplier;
will map into SQL similar to this when it is enumerated
SELECT ... WHERE Name LIKE 'Foo%'
1) Binding to The following populates a READ ONLY WinFrms grid:
Dim query = (From profile _
In db.profile _
Where profile.employee.employeeId = employeeID _
Select profile.description)
Me.DataGridView.DataSource = profileQueryList
2) Binding to the entity itself makes the WinForms grid EDITABLE, but unfiltered:
Me.DataGridView.DataSource = db.profile
I need something that combines the filtering feature of #1 with the editable feature of #2.
Try to use an explicit ToList() call.
Me.DataGridView.DataSource = query.ToList()
I guess that else only the expression tree of the query is bound and the entities are only fetched on demand.
Found the solution! It's documented in:
Linq to Entities Filtering an Entity Dynamic/Strongly Typed
Don't bind directly to the queryable. Instead, you need to go through the EntityDataSource class. Note, especially, this article on how to filter data with this control.