Entity Framework stored procedure single result set - c#

I am working with a MySQL stored procedure and trying to retrieve the single result set using EF6. My stored procedure contains the simple select statement and I have mapped it into my model. Below is the class generated by EF to map to my stored procedure
public partial class usp_aggregatedLogs_Result
{
}
It's an empty class generated by EF. I have added the properties to this class to map it to the result set returned by stored procedure.
public partial class usp_aggregatedLogs_Result
{
public int AccountId { get; set; }
public string AccountName { get; set; }
public string ProjectId { get; set; }
public string ProjectName { get; set; }
public string SystemId { get; set; }
public string SystemName { get; set; }
public string ParameterId { get; set; }
public string ParameterName { get; set; }
public Nullable<System.DateTime> TimeStamp { get; set; }
public long LogId { get; set; }
public string Type { get; set; }
}
Below is the code generated by EF in the DBContext Class
public virtual ObjectResult<usp_aggregatedLogs_Result> usp_aggregatedLogs(Nullable<System.DateTime> dateFrom, Nullable<System.DateTime> dateTo)
{
var dateFromParameter = dateFrom.HasValue ?
new ObjectParameter("DateFrom", dateFrom) :
new ObjectParameter("DateFrom", typeof(System.DateTime));
var dateToParameter = dateTo.HasValue ?
new ObjectParameter("DateTo", dateTo) :
new ObjectParameter("DateTo", typeof(System.DateTime));
return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction<usp_aggregatedLogs_Result>("usp_aggregatedLogs", dateFromParameter, dateToParameter);
}
I assume that calling this function should return me the result set returned by stored procedure. I am calling it this way
List<usp_aggregatedLogs_Result> ResultList= obj.usp_aggregatedLogs(DateFrom, DateTo).ToList();
I receive the result in my ResultList. I receive 43 objects which is correct as my stored procedure returns 43 rows. But I get no values for the properties of these objects. all properties values are either set to 0 or null.it seems like my ResultList objects are not initialized.
I don't know how to properly call my stored procedure and retrieve its result set into my application.
Please help.

I use a bit of a trick for it.
Create a view that has the same data structure as data returned by your procedure and add it to Your edmx. It doesnt have to be anything logical. Can be like:
select 1 as AccountId, 'ABC' as AccountName , (...) from x;
as long as it has correct data types. But if Your procedure only filters some data that You can put into a view I recommend doing a meaningfull view.
When mapping Your procedure in EF choose mapped view as return type.
You don't have to return the view from the procedure. You can return any data as long as it has matching structure with the view.
In C# Your procedure will now return a collection of view items.
This worked for me on MSSQL so please let me know if You managed to kick it off on MySQL.

Related

C# EF Core Procedure use with Class

I tried to use EF Core to execute a procedure, so I define a class as ACT, then use ACT class to catch procedure output, but I got this error:
Return : The required column 'A02' was not present in the results of a 'FromSql' operation.
I already know class fields and procedure have match field, but I have many procedures to use, I do I have to create a new class for each procedure ?
ACT.cs
namespace E-shop.Shared
{
public class ACT
{
[Key]
public string A01 { get; set; } = string.Empty;
public string S01 { get; set; } = string.Empty;
public string A02 { get; set; } = string.Empty;
public string A03 { get; set; } = string.Empty;
public string A04 { get; set; } = string.Empty;
public string A05 { get; set; } = string.Empty;
public int A06 { get; set; }
public int A07 { get; set; }
public int A08 { get; set; }
public DateTime A09 { get; set; }
public int A10 { get; set; }
public int? A11 { get; set; }
public int? A12 { get; set; }
public int? A13 { get; set; }
}
}
Procedure
ALTER PROCEDURE [dbo].[usp_Sel_SAcc1]
(#A01 Varchar(50))
AS
SELECT A01
FROM ACT
WHERE A01 = #A01
The method
public void CheckAccount (string Email)
{
string ProcdureName = "usp_Sel_SAcc1";
var parameter = new SqlParameter("#A01", Email);
var user = Model1_context.ACT
.FromSqlInterpolated($"EXECUTE {ProcdureName} {parameter}")
.ToList();
Console.WriteLine(user.ToString());
}
=======Update 2023/02/13 =========
Thanks every one reply!
I think I need to describe the problem in more detail!!
I got many procedure in our-project Sql, like picture at under.
Every procedure select data is not the same, But it most of use ACT Class, ACT Class is the class corresponding to the database table.
And that procedure most of them also use this table, So I wanna find a way to just use one class to catch many procedure return.
procedures example:
SACC3
ALTER Procedure [dbo].[usp_Sel_SAcc3]
(
#A01 Varchar(50)
)
AS
SELECT ACT.A04,ACT.A05,ACT.A07,ACT.A09,ACT.A03,Store.S02,Store.S09,Store.S10,Store.S13,ACT.A06,ACT.S01 FROM ACT INNER JOIN Store ON ACT.S01 =Store.S01 WHERE ACT.A01 = #A01
SAcc7
ALTER Procedure [dbo].[usp_Sel_SAcc7]
(
#S01 Char(8),
#A01 Varchar(50)
)
AS
SELECT A03,A04,A05 FROM ACT WHERE S01 = #S01 and A01=#A01
Why would you have a stored procedure that returns one column from a table, selecting by that same column? If it is more a case of selecting a record using the AO1 value then the Stored Proc would be more like:
CREATE PROCEDURE [dbo].[usp_SelectBySAcc1]
(#A01 Varchar(50))
AS
SELECT A01, A02, A03, S01, ... /* fill in all applicable fields */
FROM ACT
WHERE A01 = #A01
Then EF can populate your desired entity from the result set coming back from the stored proc. With .Net Core if any of those string columns are null-able, you will want to declare the fields as string? to avoid compiler warnings.
Your code will also likely not work as you expect. ToList() intends to load a collection of matching entities. If you are loading an entity by Key and expect just one row (or zero rows if not found) then use Single or SingleOrDefault.
var user = Model1_context.ACT
.FromSqlInterpolated($"EXECUTE {ProcdureName} {parameter}")
.Single();
Ultimately the point of EF is to not need to write SQL or stored procedures. Getting an ACT record by A01 is as simple as:
var user = Model1_context.ACT
.Single(x => x.A01 == Email);
EF will write the SQL needed to fetch the record. If you just want to check if a record exists:
var userExists = Model1_context.ACT
.Any(x => x.A01 == Email);

Xamarin.Fomrs SQLite DateTime not inserted properly through Query

In my Xamarin.Forms app, I am generating queries at api side and I directly want to execute it in my local db.
I have a table like this.
[Table("TblUnit")]
public class TblUnit
{
[AutoIncrement, PrimaryKey]
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public bool IsFavourite { get; set; }
public int WebId { get; set; }
public int CompanyId { get; set; }
public DateTime OpeningStockDate { get; set; }
}
When I try to add object using InsertAsync(object) method, object is inserted with proper date. But when I try to fire query, date is not added to database. After firing query when I try to fetch data from this table OpeningStockDate comes as 01/01/0001.
//this is generated at api side and I directly want to fire query in my local sqlite db
var query = "insert into [TblUnit] (Name,Description,IsFavourite,WebId,CompanyId,OpeningStockDate) values('Bag','Description',true,12,185,'2021-03-04 10:00:00')";
I tried changing date format to mm/dd/yyyy as well. But no success.
I tried setting storeDateTimeAsTicks flag to false.
static readonly Lazy<SQLiteAsyncConnection> lazyInitializer = new Lazy<SQLiteAsyncConnection>(() =>
{
return new SQLiteAsyncConnection(Constants.DatabasePath, Constants.Flags,false);
});
But then my entire app starts behaving incorrect. I can not get data from this table. It shows datetime parsing exception. Also can not add data to the table using InsertAsync method.
What I am doing wrong here ? Please tell me.
Thanks

Mapping stored procedures to views

I have the problem with the mapping a stored procedure to an EF entity which is represented by the view in the database.
If I try to call, for example, an .Add method - get the error
Too many parameters ...
I know/understand, that EF wants all parameters of the entity except keys (+computed) in the mapped Add - stored procedure. But in the case of "entity = view", I want to post as stored procedure parameters only some set of EF entity fields, which I have in db table (one field set in the case of insert, another set in the case of update, third set in the case of delete).
How to do this "right"? In .edmx this (mapping via graphic interface) works perfectly but I need to realize this behavior in the code-first by hands..
Example:
View in DB ..
CREATE VIEW vDepartment
AS
SELECT
d.*,
dp.Code as ParentCode, dp.SName as ParentSName,
dp.Name as ParentName
FROM
Department d
LEFT OUTER JOIN
Department dp ON d.ParentID = dp.ID
EF entity
public partial class vDepartment
{
public long ID { get; set; }
public Nullable<long> ParentID { get; set; }
public string Code { get; set; }
public string SName { get; set; }
public string Name { get; set; }
public Nullable<System.DateTime> CloseDate { get; set; }
public string ParentCode { get; set; }
public string ParentSName { get; set; }
public string ParentName { get; set; }
}
Mapping ..
modelBuilder.Entity<vDepartment>().MapToStoredProcedures(s =>
{
s.Update(u => u.HasName("udp_Department_upd"));
s.Delete(d => d.HasName("udp_Department_del"));
s.Insert(i => i.HasName("udp_Department_ins").Result(r => r.ID, "NewID"));
});
Insert stored procedure in database:
CREATE PROC [dbo].[udp_Department_ins]
#ParentID BIGINT,
#Code NVARCHAR(20),
#SName NVARCHAR(50),
#Name NVARCHAR(100),
#CloseDate DATE
AS
BEGIN
DECLARE #NewID bigint;
INSERT INTO Department...
SELECT #NewID AS NewID;
END;
you can do:
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public string ParentSName { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public string ParentName { get; set; }
to prevent ParentSName and ParentName to be offered as parameters to your stored procedure. Note that this does not mean these columns have to be actual computed columns in your database. Effectively it marks them as not updateble/readonly to EF.
I have not found a direct way to tell the mapping to ignore a parameter for a specific stored procedure, like in the edmx designer.
And do remember to add the computed columns as output of your stored procedure. This may or may not be required if these values change in the database on update.
s.Insert(i => i.HasName("udp_Department_ins").Result(r => r.ID, "NewID").Result(r => r.ParentName , "ParentName")

Quick way of mapping a stored procedure in C# EF (using Database.SqlQuery)

I have the following in a using statement:
var result = await db.Database.SqlQuery<ModelLookup>("EXEC prGetModel", new {ManufacturerId = manufacturerId}).ToListAsync();
And a ModelLookup class :
public class ModelLookup
{
public int ManufacturerId { get; set; }
public int ModelId { get; set; }
public string ModelDesc { get; set; }
}
Some of the DB columns have a different name.
Is there a quick way (or data annotation) that I can use to take a column from the database and map to the desired field?
(without having to add the procedure to a DbContext)
Thanks,

search for int id starting with x entity framework 4.1

I currently have an Entity Framework model that collects data from a legacy database and I am currently using an int on my Id properties
I am attempting to build a search box with autocomplete capabilities and want to have the autocomplete function to return a subset of records based on whether the sample id either contains or starts with (final design decision not made yet) and I am running into problems with converting the integer id to a string as I would normally use a recs.Id.toString().StartsWith(recordId) but this is apparently not supported by the Entity Framework
Is there a way around this limitation ?
My code looks like the following
Model:
public class Sample
{
public Sample()
{
Tests = new List<Test>();
}
public int Id { get; set; }
public DateTime SampleDate { get; set; }
public string Container { get; set; }
public string Product { get; set; }
public string Name { get; set; }
public string Status { get; set; }
public virtual SamplePoint SamplingPoint { get; set; }
public virtual SampleTemplate SampleTemplate { get; set; }
public Customer ForCustomer { get; set; }
public virtual ICollection<Test> Tests { get; set; }
}
and the query I am currently trying to apply to this model
[HttpGet]
public JsonResult AutoComplete(string partialId)
{
var filteredSamples =
repo.AllSamples.Where( s =>
String.Compare(s.Status, "A", false) == 0
&& (s.Id.ToString()).StartsWith(partialId)
).ToList();
return Json(filteredSamples, JsonRequestBehavior.AllowGet);
}
Any ideas would be awesome I am out of ideas at this point
No matter what you do, this is going to result in some awful performance on large datasets, because you will not be able to use any indices. My recommendation would be to use a trigger or scheduled task to store the leading digit in a separate field and filter on that.
I ended up adding a view for autocomplete data and converting the data to string in the select statement and this solved my issue
Wild thought: how about your create a computed, persisted column on your database table, that converts your ID (INT) into a string?
Then you could:
put an index on that column
use a simple string comparison on that string column
Basically, you need this:
ALTER TABLE dbo.YourTable
ADD IDAsText AS CAST(ID AS VARCHAR(10)) PERSISTED
Now update you EF model - and now you should have a new string field IDAsText in your object class. Try to run your autocomplete comparisons against that string field.

Categories

Resources