linq to entities - entity-framework

I have two three tables named
Language,Language Type,Employee
Fields of Language Type are LId,LanguageType
Fields Of Language are LId,EmpId,Language fluency
Fields of Employee are EmpId ,EmpName
Relationship between Language Type and language is one –to-one, and language and Employee table is many -to –one. Problem is when I enter data in language it displays the error
A dependent property in a Referential Constraint is mapped
to a store-generated column. Column: 'LId'."}.
Even though data is being inserted in language Type but not in language table .
lINQ query is for language table is
public void AddEmpLanguage(Language language, long id)
{
using (var context = new HRMSEntities())
{
Language emp = new Language
{
EmpId = id,
LanguageFluency = language.LanguageFluency,
};
context.Language.AddObject(emp);
}
}

You can try to add the language directly to a employee object
public void AddEmpLanguage(Language language, long empId)
{
using (var context = new HRMSEntities())
{
Language lang = new Language
{
LanguageFluency = language.LanguageFluency,
};
var employee = context.Employees.Find(empId);
/* or context.Employees.FirstOrDefault(x=>x.ID == empId); */
if(employee != null){
employee.Languages.Add(lang);
}
context.SaveChanges();
}
}

Related

Execute SP using Entity Framework and .net Core

I created a web api project using .net core and entity framework.
This uses a stored procedure which returns back most of the properties of a database table defined by entity framework.
The entity framwrok does not bring back all the columns of the table. And I get an error when I call the api complaining it cannot find the missing columns when I execute the stored procedure using ,
_context.Set<TableFromSql>().FromSql("execute dbo.spr_GetValue").ToList();
I created another model class which defines the properties brought back from the SP( called NewClass).
_context.Set<NewClass>().FromSql("execute dbo.spr_GetValue").ToList();
This works, but just wanted to check if there is a convention that the SP should only return the model classes from the database.
The SQL query must return data for all properties of the entity or query type
For this limitation, it is caused when mapping the sql query result to Model. It loop through the properties in model and try to retrive the values from query result. If the model properties are not exist in query result, it will throw error.
If you want to return required columns instead of all columns, one options is to define the returned model by Query.
For your demo code, you may define this in OnModelCreating.
builder.Query<TableFromSql>();
Note, for this way, you need to make sure all properties in TableFromSql exist in execute dbo.spr_GetValue.
For another way, you may implement your own FromSql which will add condition to check whether the properties are exist in query result.
public static class DbContextExtensions
{
public static List<T> RawSqlQuery<T>(this DbContext context,string query)
{
using (var command = context.Database.GetDbConnection().CreateCommand())
{
command.CommandText = query;
command.CommandType = CommandType.Text;
context.Database.OpenConnection();
using (var result = command.ExecuteReader())
{
var entities = new List<T>();
return DataReaderMapToList<T>(result);
}
}
}
public static List<T> DataReaderMapToList<T>(IDataReader dr)
{
List<T> list = new List<T>();
T obj = default(T);
while (dr.Read())
{
obj = Activator.CreateInstance<T>();
foreach (PropertyInfo prop in obj.GetType().GetProperties())
{
if (ColumnExists(dr, prop.Name))
{
if (!object.Equals(dr[prop.Name], DBNull.Value))
{
prop.SetValue(obj, dr[prop.Name], null);
}
}
}
list.Add(obj);
}
return list;
}
public static bool ColumnExists(IDataReader reader, string columnName)
{
return reader.GetSchemaTable()
.Rows
.OfType<DataRow>()
.Any(row => row["ColumnName"].ToString() == columnName);
}
}
Use above code like :
var result = _context.RawSqlQuery<ToDoItemVM>("execute [dbo].[get_TodoItem]");

ASP.NET Core Entity Framework SQL Query SELECT

I am one of the many struggling to "upgrade" from ASP.NET to ASP.NET Core.
In the ASP.NET project, I made database calls from my DAL like so:
var result = context.Database.SqlQuery<Object_VM>("EXEC [sp_Object_GetByKey] #Key",
new SqlParameter("#Key", Key))
.FirstOrDefault();
return result;
My viewmodel has additional fields that my object does not, such as aggregates of related tables. It seems unnecessary and counter intuitive to include such fields in a database / table structure. My stored procedure calculates all those things and returns the fields as should be displayed, but not stored.
I see that ASP.NET Core has removed this functionality. I am trying to continue to use stored procedures and load view models (and thus not have the entity in the database). I see options like the following, but as a result I get "2", the number of rows being returned (or another mysterious result?).
using(context)
{
string cmd = "EXEC [sp_Object_getAll]";
var result = context.Database.ExecuteSQLCommand(cmd);
}
But that won't work because context.Database.ExecuteSQLCommand is only for altering the database, not "selecting".
I've also seen the following as a solution, but the code will not compile for me, as "set" is really set<TEntity>, and there isn't a database entity for this viewmodel.
var result = context.Set().FromSql("EXEC [sp_Object_getAll]");
Any assistance much appreciated.
Solution:
(per Tseng's advice)
On the GitHub Entity Framework Issues page, there is a discussion about this problem. One user recommends creating your own class to handle this sort of requests, and another adds an additional method that makes it run smoother. I changed the methods slights to accept slightly different params.
Here is my adaptation (very little difference), for others that are also looking for a solution:
Method in DAL
public JsonResult GetObjectByID(int ID)
{
SqlParameter[] parms = new SqlParameter[] { new SqlParameter("#ID", ID) };
var result = RDFacadeExtensions.GetModelFromQuery<Object_List_VM>(context, "EXEC [sp_Object_GetList] #ID", parms);
return new JsonResult(result.ToList(), setting);
}
Additional Class
public static class RDFacadeExtensions
{
public static RelationalDataReader ExecuteSqlQuery(
this DatabaseFacade databaseFacade,
string sql,
SqlParameter[] parameters)
{
var concurrencyDetector = databaseFacade.GetService<IConcurrencyDetector>();
using (concurrencyDetector.EnterCriticalSection())
{
var rawSqlCommand = databaseFacade
.GetService<IRawSqlCommandBuilder>()
.Build(sql, parameters);
return rawSqlCommand
.RelationalCommand
.ExecuteReader(
databaseFacade.GetService<IRelationalConnection>(),
parameterValues: rawSqlCommand.ParameterValues);
}
}
public static IEnumerable<T> GetModelFromQuery<T>(
DbContext context,
string sql,
SqlParameter[] parameters)
where T : new()
{
DatabaseFacade databaseFacade = new DatabaseFacade(context);
using (DbDataReader dr = databaseFacade.ExecuteSqlQuery(sql, parameters).DbDataReader)
{
List<T> lst = new List<T>();
PropertyInfo[] props = typeof(T).GetProperties();
while (dr.Read())
{
T t = new T();
IEnumerable<string> actualNames = dr.GetColumnSchema().Select(o => o.ColumnName);
for (int i = 0; i < props.Length; ++i)
{
PropertyInfo pi = props[i];
if (!pi.CanWrite) continue;
System.ComponentModel.DataAnnotations.Schema.ColumnAttribute ca = pi.GetCustomAttribute(typeof(System.ComponentModel.DataAnnotations.Schema.ColumnAttribute)) as System.ComponentModel.DataAnnotations.Schema.ColumnAttribute;
string name = ca?.Name ?? pi.Name;
if (pi == null) continue;
if (!actualNames.Contains(name)) { continue; }
object value = dr[name];
Type pt = pi.DeclaringType;
bool nullable = pt.GetTypeInfo().IsGenericType && pt.GetGenericTypeDefinition() == typeof(Nullable<>);
if (value == DBNull.Value) { value = null; }
if (value == null && pt.GetTypeInfo().IsValueType && !nullable)
{ value = Activator.CreateInstance(pt); }
pi.SetValue(t, value);
}//for i
lst.Add(t);
}//while
return lst;
}//using dr
}

AspNetUserRoles not in EDMX when generating from database

I have did some searching around on this issue and have come across a few questions in regards to AspNetUserRoles not being in the EDMX designer when generating from the database. However its in the ModelBrowser and I can't get this table to show up so I can use Roles Authorization.
When I hit this method in my Roles class
public override string[] GetRolesForUser(string username)
{
DTE = new DatabaseTestingEntities();
string userID = DTE.AspNetUsers.Where(w => w.Email == username).Select(s => s.Id).FirstOrDefault();
string roleID = DTE.AspNetUsers.Include("AspNetRoles").Where(s => s.Id == userID).FirstOrDefault().ToString();//.AspNetUserRoles.Where(w => w.UserId == userID).Select(s => s.RoleId).FirstOrDefault();
string roleName = DTE.AspNetRoles.Where(w => w.Id == roleID).Select(s => s.Name).FirstOrDefault();
string[] results = { roleName };
return results;
}
The results always come back as null..
However it should look like this instead
public override string[] GetRolesForUser(string username)
{
DTE = new DatabaseTestingEntities();
string userID = DTE.AspNetUsers.Where(w => w.Email == username).Select(s => s.Id).FirstOrDefault();
string roleID = DTE.AspNetUserRoles.Where(w => w.UserId == userID).Select(s => s.RoleId).FirstOrDefault();
string roleName = DTE.AspNetRoles.Where(w => w.Id == roleID).Select(s => s.Name).FirstOrDefault();
string[] results = { roleName };
return results;
}
But that way throws an error because the AspNetUserRoles isn't in the EDMX designer when I generate the EF from the database.
How can I get this table to appear so I can continue on with what I need to do?
I have tried updating the EDMX and that doesn't work either.
I just had this question myself more or less... "Where is the AspNetUserRoles table in the model?"
My understanding is that the AspNetUserRoles table is created and consists of two foreign keys, one to the AspNetUsers table for it's Id value, and one to the AspNetRoles table, also for its Id value. When you assign a role to a user, it adds a row into the AspNetUserRoles table so as to give you what is called a "Navigation Property" on the AspNetUsers table. Look at your edmx and find the AspNetUsers table, at the bottom you'll see a Navigation Property of "AspNetRoles" and this collection is available to you in code on an AspNetUser object.
As a user can belong to many roles, this Navigation Property is a collection that can be assigned to a List something like this:
AspNetUser selectedUser = dbContext.AspNetUsers.FirstOrDefault(u => u.UserName == "foo");
if (selectedUser == null) return;
List<AspNetRole> selectedUsersRoles = selectedUser.AspNetRoles.ToList();
For the original poster's I would return the List and work with that...
public override List<AspNetRoles> GetRolesForUser(string username)
{
DTE = new DatabaseTestEntities();
AspNetUser selectedUser = DTE.AspNetUsers.FirstOrDefault(u => u.UserName == username);
if (selectedUser == null) return null; //User not found - return null
return List<AspNetRole> selectedUsersRoles = selectedUser.AspNetRoles.ToList();
}
This basically means you don't "need" the AspNetUserRoles table explicitly. You should be able to work with a user's roles as noted above. I'm not sure if it's recommended or not, but I would not directly insert into the AspNetUserRoles table either. You should just add a role to the user object and let the UserRoles table update automatically.

How do I execute "select distinct ename from emp" using GreenDao

How do I execute "select distinct ename from emp" using GreenDao
I am trying to get distinct values of a column of sqlite DB using GreenDao. How do I do it? Any help appreciated.
You have to use a raw query for example like this:
private static final String SQL_DISTINCT_ENAME = "SELECT DISTINCT "+EmpDao.Properties.EName.columnName+" FROM "+EmpDao.TABLENAME;
public static List<String> listEName(DaoSession session) {
ArrayList<String> result = new ArrayList<String>();
Cursor c = session.getDatabase().rawQuery(SQL_DISTINCT_ENAME, null);
try{
if (c.moveToFirst()) {
do {
result.add(c.getString(0));
} while (c.moveToNext());
}
} finally {
c.close();
}
return result;
}
Of course you can add some filter-criteria to the query as well.
The static String SQL_DISTINCT_ENAME is used for performance, so that the query string doesn't have to be built every time.
EmpDao.Properties and EmpDao.TABLENAME is used to always have the exact column-names and table-names as they are generated by greendao.

Can OpenJPA be used to reverse map a database view?

I have database views that have a column that uniquely identifies each row in the view. This column could be used as the primary key even though the view doesn't have a primary key in its definition (DDL) because it's a view.
OpenJPA is refusing to map the views to Java POJOs because there is no primary key.
I have a list of views and primary keys and I have a ReverseCustomizer. Is it possible I can give OpenJPA the column/field to be used as the primary key / id for each view / class?
Currently, the reverse mapping tool calls unmappedTable for each view and I'd like to tell the reverse mapper to do the mapping with the primary key I provide.
Here's something to help you get started.
public class MyDBReverseCustomizer implements ReverseCustomizer {
private ReverseMappingTool rmt;
#Override
public void setTool(ReverseMappingTool rmt) {
this.rmt = rmt;
}
#Override
public boolean unmappedTable(Table table) {
// this method is called to give this class an opportunity to map the
// table which would not be mapped otherwise. Returning false says
// the table wasn't mapped here.
//Class klass = rmt.generateClass(table.getIdentifier().getName(), null);
String packageName = rmt.getPackageName();
String tableName = table.getIdentifier().getName();
String className = NameConverters.convertTableName(tableName);
Class klass = rmt.generateClass(packageName+"."+className, null);
ClassMapping cls = rmt.newClassMapping(klass, table);
Column pk = null;
for ( Column column : table.getColumns() ) {
String columnName = column.getIdentifier().getName();
String fieldName = rmt.getFieldName(columnName, cls);
Class type = rmt.getFieldType(column, false);
FieldMapping field = cls.addDeclaredFieldMapping(fieldName, type);
field.setExplicit(true);
field.setColumns(new Column[]{column});
// TODO: set the appropriate strategy for non-primitive types.
field.setStrategy(new PrimitiveFieldStrategy(), null);
if ("MODEL_VIEW".equals(tableName) && "MODEL_ID".equals(columnName)) {
pk = column;
field.setPrimaryKey(true);
}
customize(field);
}
//cls.setPrimaryKeyColumns(new Column[]{pk});
cls.setObjectIdType(null, false);
cls.setIdentityType(ClassMapping.ID_DATASTORE);
cls.setStrategy(new FullClassStrategy(), null);
return true;
}
...
}