Below is my code for entity and a function where I need to map entity TblEmployee from a key value pair.
In foreach loop I am getting values based on keys, what should be the best approach to do it?
public class TblEmployee
{
public int EmployeeId { get; set; }
public string Name { get; set; }
}
public int Create()
{
tblEmployee employee = new tblEmployee();
using (var ctx = new theparkeee_testEntities())
{
foreach (string key in HttpContext.Current.Request.Form.AllKeys)
{
string value = HttpContext.Current.Request.Form[key];
//how to map value from key value pair to entity employee.
}
}
}
You can use System.Reflection to get the Properties of an object by their name with Type.GetProperty(string name). After you got the PropertyInfo, you can use SetValue to assign a value to it.
foreach (string key in HttpContext.Current.Request.Form.AllKeys) {
// note that "value" is a reserved word, do not use it as variable name
string val = HttpContext.Current.Request.Form[key];
var propertyInfo = typeof(TblEmployee).GetProperty(key); // can maybe be moved outside of the loop
if (propertyInfo != null) {
propertyInfo.SetValue(employee, val);
}
}
This will work for string properties. If the property is of another type, you have to find the correct type (again, using reflection) and cast the string value before assigning it.
Note that this is not the correct approach to store data in MVC. You should not work with the Request.Form directly, instead your POST action should accept a ViewModel that can be mapped (e.g. using Automapper) to the DB entity. I.e. let the ASP ModelBinder do its work, instead of reinventing the wheel!
[HttpPost]
public ActionResult Submit(MyViewModel postData) {
var employee = Mapper.Map<TblEmployee>(postData);
_ctx.Employees.Add(employee);
_ctx.SaveChanges();
return new HttpStatusCodeResult((int)HttpStatusCode.OK);
}
Related
I'm using dapper 1.50.2 with MySQL and running into a problem trying to map a left outer join child object to its parent. If I split on a column alias that doesn't actually exist in the child object, Dapper always creates a child object with default properties, even when there is nothing in the left join.
I created a simple example to demonstrate this:
public class ParentRecord
{
public string MemberID { get; set; }
public ChildRecord Child { get; set; }
}
public class ChildRecord
{
//public string Split { get; set; }
public string SomeField { get; set; }
}
using (MySqlConnection connection = new MySqlConnection(connectionString))
{
ParentRecord result = connection.Query<ParentRecord, ChildRecord, ParentRecord>(
#"SELECT 'FakeID' AS MemberID, NULL AS Split, NULL AS SomeField",
(mt, crt) =>
{
mt.Child = crt;
return mt;
},
splitOn: "Split").Single();
}
I would expect this to result a ParentRecord with the Child property set to null, but the Child property is set to a ChildRecord with all default fields.
If I uncomment the Split property in ChildRecord, or if I split on SomeField, this works as I'd expect.
Are there any good workarounds for this?
In the actual query I'm dealing with, there are multiple primary key and foreign key fields with the same names and I'd rather not change the property names in the POCOs to be unique. I'd prefer to be able to use column aliases that are just there to split on. I know this isn't normally how Dapper is set to up to work.
Any help would be appreciated, thanks.
This happen because the object Child initialize for default when you attribute the ctr param. Then the solution that I did implement was:
ParentRecord result = connection.Query<ParentRecord, ChildRecord, ParentRecord>(
#"SELECT 'FakeID' AS MemberID, NULL AS Split, NULL AS SomeField",
(mt, crt) =>
{
if (crt.SomeField != null){ mt.Child = crt; }
return mt;
},
splitOn: "Split").Single();
I have a simple query and Poco that I'm using with Dapper like so:
var jc = this.dbConnection.ExecuteScalar<JcUser>("SELECT loginid as Username,Password,coalesce(CustomerId,0) as CustomerId,TextProfileId,UxProfileId from \"user\" where id = #id", new {id = id});
Poco:
public class JcUser
{
public string UserName { get; set; }
public string Password { get; set; }
public int CustomerId{ get; set; }
public int TextProfileId { get; set; }
public int UxProfileId { get; set; }
}
When this executes it throws an exception with the message
Value is not a convertible object: System.String to JcUser
The stack trace ends up at: at System.Convert.ToType (System.Object value, System.Type conversionType, IFormatProvider provider, Boolean try_target_to_type)
Any ideas why its doing this?
Thanks
UPDATE: Using var jc = this.dbConnection.Query<JcUser>("SELECT loginid as Username,Password,coalesce(CustomerId,0) as CustomerId,TextProfileId,UxProfileId from \"user\" where id = #id", new {id = id}).First(); appears to work. I also realise I'm a moron and ExecuteScalar is only for one value. However, is my update the best way to retrieve only one row?
ExecuteScalar maps to the ADO.NET method of the same name. It returns at most one cell: one grid, one row, one column. As such, it is not intended for use with complex objects, and cannot work correctly in your case as you have multiple columns.
Dapper assumes you would only use that with simple types like int, string etc.
In your case, use:
var jc = this.dbConnection.Query<JcUser>(
sql, args).SingleOrDefault();
If you want to avoid a hidden List<> allocation you could also pass buffered: false.
Earlier I had a table named ApplicationConfiguration which simply had [Key],[Value] columns to store some config data. This was queried straight away using SQL queries.
Now I intend to make use of Entity Framework (EF) Code First approach to query this table. The specialty of this table is that the table will have only a fixed number of rows in its lifetime. Only the Value column can be updated.
So as per the code first approach, we have to first write our POCO classes with its properties that will be mapped to columns in the underlying table. However, I wish to have a Dictionary<> structure to represent these configuration KV pairs. My concern is, will EF be able to fire update queries against any updation to the the value of a particular pair.
Also since I am using Code First approach, I would want some seed data(i.e the fixed number of rows and its initial content) to the added after the table itself is created on the fly when the application is first executed.
If Dictionary<> cannot be used, please suggest some alternative. Thanks in advance.
Coded this way:
public class ApplicationConfiguration
{
public int Id { get; set; }
public string Key { get; set; }
public int Value { get; set; } // should be string, but I'm lazy
}
class Context : DbContext
{
internal class ContextInitializer : DropCreateDatabaseIfModelChanges<Context>
{
protected override void Seed(Context context)
{
var defaults = new List<ApplicationConfiguration>
{
new ApplicationConfiguration {Key = "Top", Value = 5},
new ApplicationConfiguration {Key = "Bottom", Value = 7},
new ApplicationConfiguration {Key = "Left", Value = 1},
new ApplicationConfiguration {Key = "Right", Value = 3}
};
// foreach (var c in defaults)
// context.ConfigurationMap.Add(c.Key, c); // by design, no IReadOnlyDictionary.Add
foreach (var c in defaults)
context.ApplicationConfigurations.Add(c);
base.Seed(context);
}
}
public Context()
{
Database.SetInitializer(new ContextInitializer());
}
private IDbSet<ApplicationConfiguration> ApplicationConfigurations
{
get { return Set<ApplicationConfiguration>(); }
}
public IReadOnlyDictionary<string, ApplicationConfiguration> ConfigurationMap
{
get { return ApplicationConfigurations.ToDictionary(kvp => kvp.Key, kvp => kvp); }
}
}
Used this way:
using (var context = new Context())
{
ReadConfigurationOnly(context.ConfigurationMap);
}
using (var context = new Context())
{
ModifyConfiguration(context.ConfigurationMap);
context.SaveChanges();
}
static void ReadConfigurationOnly(IReadOnlyDictionary<string, ApplicationConfiguration> configuration)
{
foreach (var k in configuration.Keys)
Console.WriteLine("{0} = {1}", k, configuration[k].Value);
}
static void ModifyConfiguration(IReadOnlyDictionary<string, ApplicationConfiguration> configuration)
{
foreach (var k in configuration.Keys)
configuration[k].Value++; // this is why I was lazy, using an int for a string
}
So, I wrote it up this way — using an int Value property rather than a string — just so I could run the "Used this way" code over and over, and see the database update each time, without having to come up with some other way to change Value in an interesting way.
It's not quite as nifty here to use a IReadOnlyDictionary<string, ApplicatonConfiguration> instead of a IReadOnlyDictionary<string, string>, the way we'd really like, but that's more than made up for by the fact that we can easily modify our collection values without resorting to a clumsier Set method taking a dictionary as input. The drawback, of course, is that we have to settle for configuration[key].Value = "new value" rather than configuration[key] = "new value", but — as I say — I think it's worth it.
EDIT
Dang! I wrote this code up specifically to answer this question, but I think I like it so much, I'm going to add it to my bag of tricks ... this would fit in really well when my company goes from local databases to Azure instances in the cloud, and the current app.config has to go into the database.
Now all I need is a ContextInitializer taking a System.Configuration.ConfigurationManager as a ctor parameter in order to seed a new database from an existing app.config ...
I don't think you can map a table directly to a Dictionary; you will probably have to write your own wrapper to fill a dictionary from the table and update it back to the DB. Entities are each a row of a given table... Something like this (untested):
public Dictionary<string, string> GetDictionary()
{
Dictionary<string, string> dic = new Dictionary<string, string>();
using (var db = new Context())
{
var configs = db.ApplicationConfiguration.Select();
foreach (var entry in configs)
{
dic.Add(config.Key, config.Value);
}
}
return dic;
}
public void SaveConfig(Dictionary<string, string> dic)
{
using (var db = new Context())
{
foreach (KeyValuePair kvp in dic)
{
if (!db.ApplicationConfiguration.First(a => a.Key == kvp.Key).Value == kvp.Value)
{
var ac = new ApplicationConfiguration();
ac.Key = kvp.Key;
ac.Value = kvp.Value;
db.Entry(ac).State = EntityState.Modified;
}
}
db.SaveChanges();
}
}
For your second question, you want to use the Seed() method to add initial values to the database. See here for an example implementation.
I'd like to know how can I make Entity Framework update an object instead of always inserting a new one for each new main object.
For example:
I have these objects:
Main Object:
public class ExtraArticleAttributes
{
[Key]
public int extraarticleattributes_id { get; set; }
virtual public WorldData world_data { get; set; }
}
Its dependencie:
public class WorldData
{
[Key]
public int worlddata_id { get; set; }
public string country { get; set; }
So, how can I make Entity Framework when inserting a new ExtraArticleAttributes verify if already exists a WorldData object and only update it?
I've been reading some articles about it and I notice that Entity Framework identify an existing object in DB with a HASH code, so when I get it from an API, and try to insert It in the DB, even though the object has the same data, the Entity Framework doesn't recognize like an existed object in DB. Does exist a way of make It, without spending request to the DB to verify if the object exists, if true get It.
Set the entity state to Modified:
using System.Data.Entity;
// Assuming that there is already an existing WorldData record in the database with id 1 and country 'foo', and you want to change the country to 'bar'
using (var context = new MyContext())
{
var extraArticleAttributes = new ExtraArticleAttributes
{
world_data = new WorldData
{
worlddata_id = 1,
country = "bar"
}
};
db.ExtraArticleAttributes.Add(extraArticleAttributes);
db.Entry<WorldData>(extraArticleAttributes.world_data).State = EntityState.Modified;
db.SaveChanges();
// world data 1 country is now 'bar'
}
I added a RIA Domain Service method to return a simple NameValuePair of two properties from a table (and filtered on a key value).
It compiles fine, but blows up every time without giving a useful error.
What am I missing? (probably something really obvious)
e.g.:
public IQueryable<NameValuePair> GetNameValues(int keyId)
{
// NOTE: I can breakpoint here and the correct keyId is passed
// it blows up on returning from this method
return from p in this.ObjectContext.NameTable
where p.KeyId == keyId
select new NameValuePair(p.NameValue, p.NameType);
}
Simple NameValuePair Code:
public class NameValuePair
{
[Key]
public string Name { get; set; }
public string Value { get; set; }
public NameValuePair()
{
}
public NameValuePair( string name, string value)
{
this.Name = name;
this.Value = value;
}
}
Update:
I tried returning a query on a static list of NameValuePair objects and that works fine (but is not useful).
I tried this here and got the error: base {System.SystemException} = {"Only parameterless constructors and initializers are supported in LINQ to Entities."}
So you have to change it to create the object first, then pass the property values:
public IQueryable<NameValuePair> GetNameValues(int keyId)
{
return from p in this.ObjectContext.NameTable
where p.KeyId == keyId
select new NameValuePair {Name = p.NameValue, Value = p.NameType};
}