late-bound stored procedure execution with Entity Framework - c#

I'm looking for a way to do something like this:
var db = new DALEntities();
db.StoredProcedureToCall();
but, I want it to be dynamic, in that I won't know WHICH call to make until after some other data is delivered to me.
var db = new DALEntities();
db[tSproc]();
I know I could have a switch statement test the value of tSproc, and then call as above, but is there a more elegant way?
Thanks

Put your cursor on db.StoredProcedureToCall() and press F12. You'll see the code that EF generated is already dynamic.
Depending on the EF version you use, it will look something like:
public ObjectResult<OrderDetail> GetDetailsForOrder
(Nullable<global::System.Int32> orderid)
{
ObjectParameter orderidParameter;
if (orderid.HasValue)
{
orderidParameter = new ObjectParameter("orderid", orderid);
}
else
{
orderidParameter = new ObjectParameter("orderid", typeof(global::System.Int32));
}
return base.ExecuteFunction<OrderDetail>("GetDetailsForOrder", orderidParameter);
}
Just write your code similarly. You don't need a switch.

Related

Teradata Query Using Dapper C#

I am trying to dynamically query a Teradata database using Dapper but am having some issues. Here is the code:
// model variable is the parameter passed in with search information
using (IDbConnection con = new TdConnection(connection.GetConnectionString()))
{
var builder = new SqlBuilder();
var selector = builder.AddTemplate($"SELECT * FROM Temp_Table /**where**/");
if (model.Id != 0)
{
builder.Where("Id = ?", new { model.Id });
}
if (!string.IsNullOrEmpty(model.Employee_Id))
{
builder.Where("Employee_Id = ?", new { model.Employee_Id });
}
var data= con.Query<TableModel>(selector.RawSql, model).ToList();
return data;
}
The error I am getting is:
[Teradata Database] [3939] There is a mismatch between the number of
parameters specified and the number of parameters required.
I have used very similar code to query DB2 which worked just fine; what do I need to do differently with Teradata?
Managed to figure it out. Changed the line for getting the data to:
var data= con.Query<TableModel>(selector.RawSql, selector.Parameters).ToList();
Not sure why passing in the model worked just fine in my DB2 version but not this Teradata version.
At first glance it appears to be falling through and not adding any "where" condition. Try to structure it in such a way that if it falls through then add 1=1 or a Teradata equivalent if that doesn't work.
I'm unfamiliar with the SqlBuilder() class; but if you have a way of seeing if there aren't any Where constraints added, then to add a generic one. Or, a dirtier way would be to keep a bool reference and check at the end.
Update
Try passing in the parameters:
var data= con.Query<TableModel>(selector.RawSql, selector.Parameters).ToList();

Entity Framework query table name dynamically based on input parameter

I have been working in a project which uses Entity Framework as the ORM data model to connect to the SQL database and retrieve data.
Now the basic query which is used to retrieve data is like this
ProjectDataContext dataContext = new ProjectDataContext();
var result = (from project in dataContext.Projects
select project).ToList();
Or in lambda
List<Project> lstprojects = dataContext.Projects.Take(10);
Now I would like to pass the table name dynamically based on some input parameter. How can I achieve that?
The way I am currently doing it is a bit messy.
if(tableName = "A")
{
List<A> lstOfA = dataContext.A.Take(10);
}
else if(tableName = "B")
{
List<B> lstOfB = dataContext.B.Take(10);
}
and so on...
My question is if there is a neat and clean way to do this without writing so many if else because I understand it may cause performance issues in future.
Thanks
Ok after some trial and error I have been able to do it like this-
var type = Type.GetType("A");
context.Set(type).Load();
var result = context.Set(type).Local.Cast<object>().ToList();
Hope it helps.`

LINQ to SQL does not work properly with Automapper

I have used Automapper for a long time without any difficulty for a long time and I have been trying to integrate this wonderful tool into my LINQ to SQl framework recently. I have following code:
using (var ps = new Promotionalsponsorship(constr))
{
var applicationToSave = Mapper.Map<ApplicationModel, Application>(application);
if (applicationToSave.ApplicationId == default(int))
{
ps.Application.InsertOnSubmit(applicationToSave);
}
ps.Application.Context.SubmitChanges();
}
What I am trying to do here is UPSERT method where I am saying that if there is anew record with id = 0 then insert OR update. Funny thing here is that insert works BUT ps.Application.Context.SubmitChanges(); does not work when I update the context using Automapper as I did that in the code above.
Now, if I update context using simple property assignment like following:
applicationToSave.Name = "Beautiful";
if (applicationToSave.ApplicationId == default(int))
{
ps.Application.InsertOnSubmit(applicationToSave);
}
ps.Application.Context.SubmitChanges();
This one works. I feel like Automapper does something to context object which makes it detached from the DB. I am not sure. How can I make it work with AutoMapper?
Change tracking only works for loaded entities. Automapper is creating a new object for you, which is completely unrelated to EF - it's just a normal object as far as the code cares. You'll need to do something like this:
using (var ps = new Promotionalsponsorship(constr))
{
var applicationToSave = ps.Application.Find(application.ApplicationId);
if (applicationToSave == null)
applicationToSave = new Application();
Mapper.Map(application, applicationToSave); //May not be accurate, search for the
//method that writes into an existing object
if (applicationToSave.ApplicationId == default(int))
{
ps.Application.InsertOnSubmit(applicationToSave);
}
ps.Application.Context.SubmitChanges();
}
That is, you load the existing application (or create a new one), then fill it with automapper.

Call a Scalar valued function in entity framework 6

How can I call a scalar function in entity framework 6 ?
I have tried the following code
using (MhEntities DContext = new MhEntities())
{
var Account_IdParameter = Account_Id.HasValue ? new ObjectParameter("Account_Id", Account_Id) : new ObjectParameter("Account_Id", typeof(long));
string res = ((IObjectContextAdapter)DContext).ObjectContext.CreateQuery<string>("MoneyforHealthEntities.Fn_LEVEL0_Acount_Id", Account_IdParameter).FirstOrDefault();
return Convert.ToInt64(res);
}
No need to use ObjectContext to do this. Also, I don't think you can simply pass in the name of the function, you need to give it complete, valid SQL.
So I would try something like this instead:
using (MhEntities DContext = new MhEntities())
{
string res = DContext.Database.SqlQuery<string>("SELECT MoneyforHealthEntities.Fn_LEVEL0_Acount_Id(#p0)", Account_Id).FirstOrDefault();
return Convert.ToInt64(res);
}
Since you didn't give any details about which database you are using, or the exact function definition, it's possible that the above may need further tweaking. But it should at least give you the basic idea.
DateTime ServerTime = new ContextDbEntities().Database.SqlQuery<DateTime>("Select getdate();").FirstOrDefault();
MessageBox.Show(ServerTime.ToString());
All the answers right but if someone uses a stored procedure, it needs to be edit on function import by:
1. Right-click on your function then click on edit.
2. On the edit function Import window.
3. Select Scaler on the returns a collection section.
4. Finally, click ok and save your model.
In my example, I call an Insert stored procedure that returns a string value.
using (DbModel db = new DbModel())
{
string result = db.storedprocedureName(value1,value2).FirstOrDefault();
return result;
}

Is there a way to load sql data types into a drop down without having to write my own method

I would like to create a drop down similar to the drop down for sql data types in the data mapping section in the Import/Export Wizard in Sql Management Studio.
Does anyone know how to do this without writing custom code to do so? Would there be a method call in System.Data.Sql that would perform this?
Just for posterity, this is not that hard to do - run this in Linqpad with a reference to System.Data:
void Main()
{
Console.WriteLine(GetSqlTypes());
}
Dictionary<string,Type> GetSqlTypes()
{
var types=new Dictionary<string,Type>();
var a = Assembly.Load("System.Data");
foreach (var sqlType in a.GetTypes().Where(t=>t.Namespace=="System.Data.SqlTypes"
&& t.Name.StartsWith("Sql")
&& !t.Name.Contains("Exception")
&& !t.Name.Contains("Schema")
&& !t.Name.Contains("Stream")))
{
types.Add(sqlType.Name,sqlType);
}
return types;
}
So you can just bind your dropdown to GetSqlTypes:
ddlTypes.DataSource = GetSqlTypes();
ddlTypes.DataTextField = "Value";
ddlTypes.DataValueField = "Key";
ddlTypes.DataBind();
Of course this is a pure brute-force hack and no doubt someone else has a more elegant way to do it, but this will at least get you up and running.
System.Enum.GetValues(typeof(System.Data.SqlDbType));
There is no built in method to do that.

Categories

Resources