I have a very simple question and would be great if someone could save me some typing in the future.
I see myself typing this statement often:
using (DataClasses1DataContext db = new DataClasses1DataContext())
I remember seeing a shorter version of it somewhere but can seem to find it. I believe it has the name of the datacontext only typed once.
Thanks!
Like this?
using (var db = new DataClasses1DataContext())
To abbreviate it even further you could do something like this:
using (var db = DataClass.DB())
Where DataClass has a static method DB that returns a new instance of your data context.
using (var db = new DataClasses1DataContext())
I still have to do this too, usually in a repository. The only difference as others answered is to use the var db implicit definition. This works because you are instantiating a class explicitly with the new keyword so the compiler still knows that the type will be DataClasses1DataContext
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 have more of a theoretical question. If someone could provide me only a link to answer I will be happy as well I just have no idea how to look it up on the internet, so I haven't found an answer.
Lets say I have a class that should check if there is no corrupted data in database. So I have it in normal method etc, with
using (var databaseContext = new ExambleDBEntities())
Purpose of this method is to check if there is corrupt data - and if there is, to repair it. But it is not question about the code itself, so excuse me for not giving any. It is about... what can I do with data from database.
So I have connection to database, database context is set, query done, I have my first date in let's say "TableName dataSample".
Main question is:
Can I send this "dataSample" to other method inside the same function, where it will be changed and then save changes in main method?
Does the ObjectContext keep track of what was taken from database and remember what to save or it MUST be in the same method, under using directive?
I think what I wrote is not clear enough so maybe I'll write some example code:
void MainMethod()
{
using (var databaseContext = new ExambleDBEntities())
{
var DatabaseQuery = from... select... ;
TableName dataSample = DatabaseQuery.First();
dataSample = CorrectMistakes(dataSample);
databaseContext.SaveChanges();
}
}
TableName CorrectMistakes(TableName sample)
{
if (somethingWrong)
sample.money = 0;
return sample;
}
And should I return changed object or can I just edit inside other method?
Sorry for any mistakes, I had really hard time explaining that in English.
Thank you for any help and here is stuff I use in case anyone needs it: Visual Studio 2012, .NET Framework 4.5, MySQL Connector 6.9.4, MySQL for VS 1.2.3.
Yes, you can do that. Sorry, I don't have a link for you, but I just ran a test to be sure and it worked. It shouldn't be too difficult for you to also test this to confirm that it works.
Because you are calling CorrectMistake() inside the using directive, any changes it makes to the TableName object will stay within the current context and be saved when you call SaveChanges().
Can I send this "dataSample" to other method iside the same function, where it will be changed and then save changes in main method?
Yes, you can. Try it out!
Do ObjectContext keep track of what was taken from database and remember what to save or it MUST be in the same method, under using directive?
Yes and no. It "remembers" while you are in the using directive. It doesn't really matter about which method is doing the work, so long as the work is being done while in the using block.
And should I return changed object or can I just edit inside other method?
It doesn't matter, either will work. Do whatever is most appropriate for your situation. If you are just making a change to one of the object's properties, then it probably makes more sense to edit inside the method.
Consider this simple example:
private void ChangeObject(object obj)
{
if (something)
obj.Name = "New name";
}
using (var db = new Context())
{
var obj = db.Objects.First();
ChangeObject(obj);
db.SaveChanges();
}
this is equivalent to:
using (var db = new Context())
{
var obj = db.Objects.First();
if (something)
obj.Name = "New name";
db.SaveChanges();
}
I have generated a list of public classes that need to be added into an SQLite database.
I get the class names like this
private List<Type> types = new List<Type>();
...
var pathName = Directory.GetFiles(string.IsNullOrEmpty(dirPath) ? "SQLClasses" : dirPath);
foreach (var path in pathName)
types.AddRange(Assembly.LoadFrom(path).GetTypes());
types now contains my classes that need to be turned into SQLite tables.
Normally, I would create my tables like this
using (SQLiteConnection sqlCon = new SQLiteConnection(DBPath))
{
sqlCon.CreateTable<TableName>();
As I already have my list of classes held in types, I'm trying to insert these tables into the database using a simple foreach
Currently I have this
foreach(var t in types)
{
var T = Activator.CreateInstance(t);
sqlCon.CreateTable<T>();
}
neither this nor the simpler
sqlCon.CreateTable<typeof(t)>();
or
sqlCon.CreateTable<t>();
work (all three give T [or t] doesn't exist in the current context)
Can I use this simple foreach method to insert the table names or do I have to do something more complex?
The answer is that CreateTable has two overloaded methods
sqlCon.CreateTable<T>();
and
sqlCon.CreateTable(t);
the second allowing for a type to be used rather than a generic class of T to be used. I was unaware of this second method until I noticed some obscure reference on a website than mentioned a second method but failed to say what it was. Digging around found this.
My apologies for not providing a fuller answer earlier
I'm apologizing if I'm using the wrong terminology here. I'm still very much in the ORM world, but I've been playing around with MongoDb and really love what I see. One of the things I'm not liking is this:
var books = bookRepository.GetCollection<BsonDocument>("books");
And
foreach (var book in books.FindAllAs<Book>())
{
Console.WriteLine("Author: {0}, Title: {1}", book.Author, book.Title);
}
I've found several tutorials on wrapping NoRM in a session but I can't figure out how to do it using the CSharp Drivers (the ones that Mongodb recommends / has on their github page).
What I'd really like to do is something like this for the first example:
var bookRepository = MongoRepository<Book>(); // probably should use IoC to resolve this
and
foreach (var book in books.FindAll())
Voila! I'm probably not the first person to want this, using strings everywhere seems a bit nutty, though I will grant that the tutorial is just an example. Is there a "best practices" example to setting this all up in such a manner?
Edit: Please let me know if this is crazy talk and not how to do things in Mongo, again this is my first test project.
Here is snippet from my project:
public static MongoCollection<T> GetCollection<T>(string collectionName = null)
{
if (string.IsNullOrWhiteSpace(collectionName))
{
Type g = typeof (T);
collectionName = g.Name;
}
return MongoServer.Create(Config.MongoConnectionString).GetDatabase(Config.Database).GetCollection<T>(collectionName);
}
Now I dont need to specify a collection name as a string unless I want to override it:
var collection = GetCollection<MyEntity>();
or
var collection = GetCollection<MyEntity>("SomeOtherCOllection");
You can use some inflection utility\library to pluralize your collection names if you want.
Also, you dont need to specify the type in your Find methods if you specified the type when instantiating a collection class, like I have above.
For example, this is how I do it:
MongoCursor<MyEntity> results = collection.FindAll();
or
MongoCursor<MyEntity> results = collection.Find(query);
I have a setup where I used Linq2SQL inheritance. To make queries easier, I expose the derived types in the DataContext as well, like the following:
public IQueryable<Derived> Derivations
{
get { return Bases.OfType<Derived>(); } // filter list on type
}
Calling this works perfectly, and I can see the SQL being correctly generated. The backing type is DataQuery<T>.
The problem comes in when I assigning this IEnumerable to a datasource (either a control or a BindingSource).
From what I can see, the DataQuery object is queried for an IListSource. And it happily supplies this. Then it proceeds to make a BindingList, which fails as the type parameter of the 2 arguments supplied (IEnumerable<Derived> and Table<Base>) does not match. It raises an exception of MissingMethod as the constructor cannot be found.
The simple workaround is just to call ToList() on the IQueryable<Derived> before assigning to the datasource and then it works, but this is quite tiring.
Any suggestions to handle this without 'loosing' the IQueryable?
Thanks
leppie
UPDATE:
The bug has now been reported to MS. More details here. Thanks Marc!
Confirmed. Looks like a bug to me; you should log it on Connect. The team are fixing LINQ-to-SQL bugs, so it might not be ignored. For now, use .ToList() etc.
Sample code:
using (var ctx = new MyDataContext())
{
var qry = ctx.BaseEntities.OfType<DerivedEntity>();
IListSource ls = (IListSource)qry;
IList list = ls.GetList(); // boom
/* Constructor on type
'System.Data.Linq.Provider.DataBindingList`1[snip]'
not found.*/
}
I had the same issue (still not fixed MS guys!).
To keep the IQueryable I did a .Cast<object>() when assigning to the datasource (i use it to output a xls file from any L2S table i want in a DynamicData website).