I'm creating some manual SQL updates using C#, Entity Framework 4 and DB2, in the way of this naive example...
var UpdateCommand = "UPDATE MY_SCHEMA." + this.Entities.PRODUCT.EntitySet.Name +
" SET STOCK=0";
var AffectedRows = this.Entities.ExeceuteStoreCommand(UpdateCommand);
I want to specify the schema as with the entity name (which later, if implememented in a reusable library method, could be passed as parameter). So, I tried...
var Container = this.Entities.MetadataWorkspace.GetEntityContainer(this.Entities.DefaultContainerName, System.Data.Metadata.Edm.DataSpace.CSpace);
var Set = Container.GetEntitySetByName(this.Entities.PRODUCT.EntitySet.Name, true);
var SchemaName = Set.MetadataProperties["Schema"].Value;
The problem is that the SchemaName returned is always null!
I've seen solutions based on parsing SQL generated by Entity Framework, but that could be fooled (text can containg anything), or SQL-Server specific. The idea is to be as DB agnostic as EF is.
Question is... how to get an entity schema name from EF objects, not parsing generated SQL and being db-agnostic?
you can get it from SSpace.
In ef5 following works. Probably will work in ef4 also
// for code-first
var Container = this.Entities.MetadataWorkspace.GetEntityContainer("CodeFirstDatabase", DataSpace.SSpace);
// db-first
var Container = this.Entities.MetadataWorkspace.GetEntityContainer("DbFirstModelStoreContainer", DataSpace.SSpace);
var schemaName = Container.GetEntitySetByName(this.Entities.PRODUCT.EntitySet.Name, true).Schema
// or
var set = Container.GetEntitySetByName(this.Entities.PRODUCT.EntitySet.Name, true);
var schemaName = Set.MetadataProperties["Schema"].Value;
Related
SQL Server provides output for inserted and updated record with the 'inserted' keyword.
I have a table representing a processing queue. I use the following query to lock a record and get the ID of the locked record:
UPDATE TOP (1) GlobalTrans
SET LockDateTime = GETUTCDATE()
OUTPUT inserted.ID
WHERE LockDateTime IS NULL
This will output a column named ID with all the updated record IDs (a single ID in my case). How can I translate this into EF in C# to execute the update and get the ID back?
Entity Framework has no way of doing that.
You could do it the ORM way, by selecting all the records, setting their LockDateTime and writing them back. That probably is not safe for what you want to do because by default it's not one single transaction.
You can span your own transactions and use RepeatableRead as isolation level. That should work. Depending on what your database does in the background, it might be overkill though.
You could write the SQL by hand. That defeats the purpose of entity framework, but it should be just as safe as it was before as far as the locking mechanism is concerned.
You could also put it into a stored procedure and call that. It's a little bit better than the above version because at least somebody will compile it and check that the table and column names are correct.
Simple Example #1 to get a data table:
I did this directly against the connection:
Changed the command.ExecuteNonQuery() to command.ExecuteReader()
var connection = DbContext().Database.Connection as SqlConnection;
using (var command = connection.CreateCommand())
{
command.CommandText = sql;
command.CommandTimeout = 120;
command.Parameters.Add(param);
using (var reader = command.ExecuteReader())
{
var resultTable = new DataTable();
resultTable.Load(reader);
return resultTable;
}
}
FYI, If you don't have an OUTPUT clause in your SQL, it will return an empty data table.
Example #2 to return entities:
This is a bit more complicated but does work.
using a SQL statement with a OUTPUT inserted.*
var className = typeof(T).Name;
var container = ObjContext().MetadataWorkspace.GetEntityContainer(UnitOfWork.ObjContext().DefaultContainerName, DataSpace.CSpace);
var setName = (from meta in container.BaseEntitySets where meta.ElementType.Name == className select meta.Name).First();
var results = ObjContext().ExecuteStoreQuery<T>(sql, setName, trackingEnabled ? MergeOption.AppendOnly : MergeOption.NoTracking).ToList();
T being the entity being worked on
I am using Linq-to-Entities in my Windows Application and want to execute this SQL statement:
SELECT IDENT_CURRENT ('ProductInfo') AS Current_Identity
I have read another post that is using Database.SqlQuery like this:
int varMaxAdvertiseId = Convert.ToInt32(hmd.Database.SqlQuery<decimal>("Select IDENT_CURRENT ('HMDAdvertiseManage')", new object[0]).FirstOrDefault());
but this is not working with me (intelisense is not showing it) Can someone help me, please ?
var id = hmd.ExecuteStoreQuery<decimal>(#"SELECT IDENT_CURRENT ({0}) AS Current_Identity;",
"HMDAdvertiseManage").First();
If you are using .net 4.0 to 4.8 then you should be careful that your model usually inherit from DbContext then when you want to use ExecuteStoreQuery
then you should get ObjectContext from your model
var context = new YourDbContext();
var adapter = (IObjectContextAdapter)context;
var objectContext = adapter.ObjectContext;
var id = objectContext.ExecuteStoreQuery<decimal>(#"SELECT IDENT_CURRENT ({0}) AS Current_Identity;", "HMDAdvertiseManage").First();
every things is Ok now
I want to use this query
select datename (dw, CURRENT_TIMESTAMP)AS DAY ;
to get week day name and use it to insert record to table.
how can I use this query by entity framework
I use this method but it doesn't work:
private void GetDayName(DateTime ReportDate,out string DayName)
{
using (var context = new Daily_ReportEntities3())
{
var day_name= context.ExecuteStoreQuery ("select datename (dw,'|| + ReportDate + ||') as NameOfDay", null).ToList();
DayName = day_name=.ToString();
}
}
You cannot execute transact SQL statements from Entity Framework directly.
But you can Execute Functions from within ObjectContext.
First define a scalar value function returning data you need and next import it to your Store model. You'll be able to execute it via ObjectContext.ExecuteFunction method.
PS. Consider implementing your functionality using System.Globalization.Calendar object, that can supply the information about day names based on certain culture.
Should be like this:
var day_name = context.Database.SqlQuery<string>
("select datename (dw,'|| + ReportDate + ||') as NameOfDay").FirstOrDefault<string>();
see
http://msdn.microsoft.com/en-us/library/gg696545%28v=vs.103%29.aspx
I'm using entity framework, and I need to get a list of entities only by passing the name of the entity.
Example:
string tableName = "PRODUCT";
List<tableName> myList = (from prod in dbContext.tableName
select prod).ToList();
What I can't get to do, is that, using the table name (string) to make a EF query (or LINQ).
I'm trying to get this to work by using Reflection or EntityDataModel, but I just can't.
Have you tried something like this (source):
var table = context.ExecuteStoreQuery<ResultTableTemplate>("SELECT ... FROM " + tableName);
Up to now (with NHibernate) I've used entity mapping and not really got involved with creating raw sql queries - but somethings come up where I need to do exactly that.
The problem I have is I want to automatically map the columns aliases of my query to a Dto object.
This works, but i have to specify the column alias' in the order of the query.
SQL
string sql = "select mycol1 as ColumnOne from mytable";
NHibernate Query
var query = session.CreateSQLQuery(sql)
.AddScalar("ColumnOne", NHibernateUtil.Int32)
.SetResultTransformer(
NHibernate.Transform.Transformers.AliasToBean<MyDtoObject>()
);
MyDtoObject
public class MyDtoObject
{
public int ColumnOne {get;set;}
}
But is there a way to making NHibernate automate the mapping between the columns in the query and the Dto without creating a mapping class?
I've seen some examples of using aliases in the query e.g.
string sql = "select mycol1 as {ColumnOne} as ColumnOne from mytable"; /// ???
But cannot get this to work as the alias {ColumnOne} appear not to be replaced before being sent to the db as a sql statement.
Any idea?
TIA
Sam
Maybe System.Linq.Dymanic will help:
use System.Linq.Dynamic;
string ColumnAlisName = "ColumnOne";
var query = mytable.Select(String.Format("new (mycol1 as {0})",ColumnAlisName));