I have a class that I need to hydrate from a DataTable object. Usually I do this the manual way. (see code snipit). The DataTable object populated using ADO.NET and TSql. I need to transfer the values from the DataTable into my .NET class. Is there a utility method that will do this for me automagically? So that I can avoid repetitive code like the following?
DriverSummary driver = new DriverSummary();
driver.Id = (int)row["Id"];
driver.UserId = row["UserId"] as string;
driver.Name = row["Name"] as string;
driver.TruckType = row["TruckType"] as string;
summaries.Add(driver);
I know that the Entity Framework is a tool that is supposed to fill this gap. I haven't quite made the jump to Entity Framework. For now I'd like to have a method that is similar to MVC's utility method UpdateModel() Which is lightweight and simple and hydrates a class from a list of form-value pairs by matching up key names with property names.
Such a utility method would save me tons of time!
Like mentioned above I believe AutoMapper can do this now. You could also look at a ValueInjecter. ValueInjecter and DataTable
Related
Please, please don't close or mark this question as duplicate, I have already looked StackOverflow and online but couldn't find solution.
Below code works great that I receive data from SQL Server via a stored procedure, then assign to a list of book model and return Json:
public IActionResult GetAllBooks()
{
List<BookViewModel> book = new List<BookViewModel>();
DataTable dataTable = new DataTable();
using (SqlConnection sqlConnection = new SqlConnection(_configuration.GetConnectionString("xxx")))
{
sqlConnection.Open();
SqlDataAdapter sqlData = new SqlDataAdapter("proc_GetBookList", sqlConnection);
sqlData.SelectCommand.CommandType = CommandType.StoredProcedure;
sqlData.Fill(dataTable);
foreach (DataRow dr in dataTable.Rows)
{
book.Add(new BookViewModel
{
Name = dr["Name"].ToString(),
Stock = Convert.ToInt32(dr["Stock"]),
});
}
}
return Json(book);
}
But I am trying to find a better way or best practice e.g serialize or any other techniques so that I don't need to create (View model and Assigning them values) like below. This is small example of only two properties but sometimes I need to map like 20 or more properties, do you guy see any problem in above code? I am new in software development world, any suggestion would be appreciated.
new BookViewModel
{
Name = dr["Name"].ToString(),
Stock = Convert.ToInt32(dr["Stock"]),
};
I have used Newtonsoft JSON (NuGet package) for this purpose.
Example:
using Newtonsoft.JSON;
public string DataTableToJSONWithJSONNet(DataTable table) {
string JSONString = string.Empty;
JSONString = JSONConvert.SerializeObject(table);
return JSONString;
}
You can find this Newtonsoft example and a few other methods here.
Using a query like you are using is pretty much going to make you use this style of assignment. Switching to Entity Framework to query your DB is going be your best bet, since it will do assignment to objects/classes automatically. But I get that doing so after a project is started can be a PITA or nearly impossible (or a very significantly large amount of work) to do. There's also a bit of a learning curve, if you've never used it before.
What you can do to make things easier is to create a constructor for your model that takes in a DataRow and assigns the data on a single place.
public BookViewModel(DataRow dr)
{
Name = dr["Name"].ToString();
Stock = Convert.ToInt32(dr["Stock"]);
}
Then you just call "book.Add(new BookViewModel(dr));" in your foreach loop. This works well if you have to do this in multiple places in your code, so you don't have to repeat the assignments when you import rows.
You might also be able to use Reflection to automatically assign the values for you. This also has a bit of a learning curve, but it can make conversions much simpler, when you have it set up.
Something similar to Reflection is AutoMapper, but that's not as popular as it used to be.
I was going to suggest using a JSON package like Newtonsoft or the built in package for C#, but it looks I got beat to that punchline.
Another option is using Dapper. It's sort of a half-step between your current system and Entity. It can use SQL or it's own query language to cast the results directly to a model. This might be the easiest and most straight forward way to refactor your code.
Dapper and Entity are examples of object relational mappers (ORMs). There are others around you can check out.
I've only listed methods I've actually used and there are many other ways to get the same thing done, even without an ORM. They all have their pros and cons, so do your research to figure out what you're willing to commit to.
Simply just replace your "return Json(book)" with
return Ok(book)
I want to make a generalized Data Table to Linq Collection
I am a beggginer so if it's not possible please let me know
public void Something(DataTable dt)
{
var data = from row in dt.AsEnumerable()
select new {
Order = row["Order"].ToString(),
Something = row["Something"].ToString(),
Customer = row["Customer"].ToString(),
Address = row["Address"].ToString()
};
}
That is the code for one table
i want something like this:
public static void convertDatatable(DataTable dt)
{
var results = from myRow in dt.AsEnumerable()
select new
{
foreach(DataColumn column in dt.Columns)
column.ColumnName // linq Variable name
= myRow[column.ColumnName];// linq Variable Value
};
}
I know it doesn't work how i wrote it but is there another way ?
Note: the reason i am doing this is because i can't convert Datatable directly to JSON it serializes it to XMl then sends it as a string containing that xml.
If you want to stay with datatables then there is this, mentioned in another SO: What should I use to serialize a DataTable to JSON in ASP.NET 2.0?, which links to What should I use to serialize a DataTable to JSON in ASP.NET 2.0?.
I highly recommend, however, that you consider moving away from DataTables and DataRows, replacing it instead with an ORM such as Entity Framework (EF Quick Start here) or Linq to Sql - there are others, but since you are a beginner these offer the easiest learning curve; not least because of the full designer support in Visual Studio.
For the standard forms of JSON serialization offered by .Net (e.g. WCFs DataContractSerializer or the Asp.Net JSON serializer) then you need concrete types. The ORM solution will create all your table wrapper types at design-time, giving you a concrete type, potentially, for every table in your database.
As for the idea you've specifically outlined above, it is exceptionally difficult to achieve - because the compiler, in the first example, dynamically generates a type whose members match the names and types of the expressions you use. If you open your compiled code in ILSpy and switch to IL instead of C# you'll see what I mean.
Therefore, to reproduce it dynamically you would need to dynamically emit a class, probably using ILGenerator, doing the same thing; and then dynamically emit the expression tree (using the Expression class' static factory methods) to fill it out; and finally compile and execute it.
I would only look at doing something like that if I literally couldn't do it any other way - I'd be more likely to just write a routine to iterate through each column and write the JSON to a StringBuilder and return that! But if I could use an ORM, then I'd do that instead.
I'm trying to create objects dynamically but I don't know how to. What I need is, I have a class for that object, and objects properties are stored in the database. Then I'll need to compare the properties of each object to get the desired result.
So I need to dynamically create objects on the fly with the properties loaded from database.
I don't think you need to create objects dynamically, just create one statically that matches your db schema with the property details, then you can compare the values of the properties across rows, or within an instance of your object.
I have been working on something similar to this. There are several things:
Include the System.Reflection namespace
Create an object dynamically using Activator
Get the object properties using the myObjectType.GetProperties() method
Here is an example of a generic object creation function using the above methods:
using System.Reflection;
public static Item CreateItem<Item>(object[] constructorArgs, object[] propertyVals)
{
//Get the object type
Type t = typeof(Item);
//Create object instance
Item myItem = (Item)Activator.CreateInstance(t, constructorArgs);
//Get and fill the properties
PropertyInfo[] pInfoArr = t.GetProperties();
for (int i = 0; i < pInfoArr.Length; ++i)
pInfo.SetValue(myItem, propertyVals[i], null); //The last argument is for indexed properties
return myItem;
}
Of course the above example assumes that the values in the property value array are arranged correctly, which is not necessarily the case, but you get the idea.
With the PropertyInfo class you can get properties, get property names, get attributes associated with the properties, etc. Powerful technology. You should be able to do what you need with the above info, but if not let me know and I will add more info.
If you have a number of objects you want to instantiate from database values it can be done something like this.
//database code goes here, results go in results
List<ClassName> l = new List<ClassName>()
foreach(Row r in results){
l.Add(new ClassName(){ClassProperty1 = r.Property1,ClassProperty2 = r.Property2});
}
Are you talking about Dictionary?
var dict=new Dictionary<string, string>();
dict.Add("property1", "val1");
dict.Add("property2", "val2");
var prop2val=dict["property2"];
Maybe Activator is what your looking for?
http://msdn.microsoft.com/en-us/library/system.activator.aspx
Check this class, compile in the realtime. But it's performance is not quite good.
http://msdn.microsoft.com/zh-cn/library/microsoft.csharp.csharpcodeprovider(VS.80).aspx
You could use reflection to dynamically build your objects:
Reflection msdn reference
I think that you want to retrieve rows from the DB and directly assign them to object given that the properties of the object are equivalent to the columns of DB table. If that what you mean then I believe you can't :)
Rob Conery did a small project called Massive that pretty much does what you're trying to accomplish. It's essentially a small ORM, in 400 lines of Dynamic C# 4.0 code.
Rob has been doing this kind of thing for quite some time with SubSonic, so you might find his approach with Massive quite interesting.
http://blog.wekeroad.com/helpy-stuff/and-i-shall-call-it-massive
Some of the code is explained here, with examples:
http://blog.wekeroad.com/microsoft/the-super-dynamic-massive-freakshow
I am currently referencing a generic DataSet via an index and would like to convert this to a strongly-typed DataSet of the table type. The issue is that my index to the DataRow is a variable.
Currently I am doing the following where the History_Column value is pulled from the database.
e.Dr[c.History_Column.ToString()] = Entry;
I would like to define the DataRow ('Dr' in the example) as a type of the table so I can do something similar to the following:
e.Dr.COLUMN_NAME = Entry;
How can I use dynamic variables in this fashion?
Thanks!
You could use a dynamic type to get you part of the way there, but your goal sounds kind of contradictory.
dynamic Dr = new ExpandoObject();
Dr.whatever = 6;
Dr.anything = "asdf";
If you use ExpandoObject with dynamic, you can assign any property.
A strongly-typed dataset is a class in your application that derives from the built-in dataset class. You have to add them to your project in visual studio. Here are some directions for creating strongly typed datasets.
However, I suggest that you take the opportunity to refactor and get away from datasets altogether (if you can). Entity Framework provides strongly typed property accessors for each column, a better "unit-of-work" pattern, a graphical database mapping tool, and it is much easier to use.
I am able to dynamically train and create my regression model just fine from a string[] of column names. However, when I try to pass in a dynamic object with the same Parameter names as Dictionary Key Pair properties it throw the error:
System.ArgumentOutOfRangeException: 'Could not find input column '<MyColumn>'' Where <MyColumn> is the first parameter that the model is looking for.
private static void TestSinglePrediction(MLContext mlContext, dynamic ratingDataSample, int actual)
{
ITransformer loadedModel;
using (var stream = new FileStream(_modelPath, FileMode.Open, FileAccess.Read, FileShare.Read))
{
loadedModel = mlContext.Model.Load(stream);
}
var predictionFunction = loadedModel.MakePredictionFunction<dynamic, RatingPrediction>(mlContext);
var prediction = predictionFunction.Predict(ratingDataSample);
Console.WriteLine($"**********************************************************************");
Console.WriteLine($"Predicted rating: {prediction.Rating:0.####}, actual rating: {actual}");
Console.WriteLine($"**********************************************************************");
}
I suspect this is because the dynamic object doesn't contain the [Column] attributes that the standard class object I normally would pass in has.
However, I will eventually have hundreds of columns that are auto generated from transposing SQL queries so manually typing each column isn't a feasible approach for the future.
Is there any way I could perhaps apply the attribute at run time? Or any other way I can generically approach this situation? Thanks!
This is a great question. The dynamic objects don't work at runtime because ML.NET needs something called a SchemaDefinition for the objects that you pass in so that it knowns where to get the columns it expects.
The simplest way to solve your problem would be to define an object holding only the columns you need at scoring-time, annotated with Column attributes, and manually cast your dynamic object at runtime. This has the main advantage that since you do the casting to the scoring object yourself, you can handle missing data cases yourself without the ML.NET runtime throwing. While your SQL query may give you a large assortment of columns, you won't need the majority of these columns for scoring your model, and therefor don't need to account for them in the scoring object; you only have to account for the columns the model expects.
See this sample from the ML.NET Cookbook for an example of how to score a single row. Behind the scenes, ML.NET is taking the class you defined, and using attributes like Column to construct the SchemaDefinition.