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();
}
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 be able to do something like the following:
var book = new Book();
book.LoadByPrimaryKey(id); //returns bool
The issue I am coming across is I can't figure out if there is a simple way to load data into an object generated using Entity Framework. I understand how to grab the information needed to fill the object, but is there a simple way to fill out all the properties of an object without explicitly going through each property and setting it to the desired value? In C# I cannot simply type:
this = db.Books.Single(d => d.BookId == id);
I instead have to explicitly set each property:
var book = db.Books.Single(d => d.BookId == id);
this.Title = book.Title;
this.PageCount = book.PageCount;
...
Is there a way around doing this when wanting to load up an object? Maybe something with a DbDataReader? I have used the data reader to load DataTables, but can't figure out how to use them to populate an object. Maybe I'm over thinking it.
When you need to copy all of the properties from one object to another you can
Just write the code (typing practice)
Generate the code using a T4 Template
Use Reflection
Use Automapper
As David Browne previously answered:
Just write the code (typing practice)
Generate the code using a T4 Template
Use Reflection
Use Automapper
The answer he gave you is correct. But I'm want to extend it and explain why.
First, let put some concept here. When we go further in programming techniques, sometimes, the working answer, it not enough. Although what you trying to do is a valid solution for the problem, there is some issue with it.
The is a concept that is called S.O.L.I.D. The first letter (S) stands for Single Responsibility Principle. This means that one object should have only one responsibility.
The problem in your approach is you are putting multiple responsibilities in a single object:
Hold/Transport information about a book.
Load from a remote server (in this case a DataBase) information about a book.
You probably googled this issue before post here, and I suspect you found nothing useful. Now the reason you found nothing is because this is a bad approach, it goes against the SOLID concepts, and it breaks several interation with possible Design Patterns. So this is why you probably found nothing, there is no previous conceived tool of workaround to this problem, because this is a discouraged approach, so no one, with a little understand of program techniques, will help you.
Therefore, we go back to the answer that David Browne gave you. To use Automapper (the simplest of the suggestions). You need to change your approach. Consider to separate each responsibility in a different class:
class BookDA // DAO = data access
{
private MyDbConnection db;
public BookTO Get()
{
var book = db.Books.Single(d => d.BookId == id);
return book;
}
}
class BookTO // TO = transport object
{
public string Name { get; set; }
}
In the code above each responsibility is associated with a different class. This answer became too long but I hope it helps.
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
It appears that AutoMapper's methods BeforeMap and AfterMap have a critical bug, which if one is attempting to iterate over a collection of the source object to populate a property of the destination object, those mapping methods execute more than once. See: Extra iterations in a foreach in an AutoMapper map
What I'm trying to do is a bit complicated, so please bear with me.
I have a EF4 many-to-many graph (Games-to-Platforms) I'm trying to build based on incoming form data. In order to build the graph, I take the raw integer ids that come from the form, and then grab the correct Platforms from my repository in order to add them to the Game's collection. You can see my attempt at doing this within BeforeMap in the link I provided above.
The problem is that I'm not sure how to proceed. I need to be able to grab a hold of the destination (Game) object in order to successfully Add the Platforms to the Game. Is something like this possible in ForMember? From what I've read, it doesn't look like a custom resolver would work for me, and I'm not sure how I'd implement a custom type converter given all the moving parts (two entities, repository).
Any ideas or suggestions?
I simply decided to make my own static mapper. Not an ideal, or even great solution, but it works. It can definitely be made more abstract, but I figure it's a band-aid until AutoMapper is fixed. My solution:
public static class GameMapper
{
public static Game Map(IGameRepository repo, AdminGameEditModel formData, Game newGame)
{
newGame.GameID = formData.GameID;
newGame.GameTitle = formData.GameTitle;
newGame.GenreID = formData.GenreID;
newGame.LastModified = DateTime.Now;
newGame.ReviewScore = (short)formData.ReviewScore;
newGame.ReviewText = formData.ReviewText;
newGame.Cons = String.Join("|", formData.Cons);
newGame.Pros = String.Join("|", formData.Pros);
newGame.Slug = formData.Slug;
if (newGame.Platforms != null && newGame.Platforms.Count > 0)
{
var oldPlats = newGame.Platforms.ToArray();
foreach (var oldPlat in oldPlats)
{
newGame.Platforms.Remove(oldPlat);
}
}
foreach (var platId in formData.PlatformIDs)
{
var plat = repo.GetPlatform(platId);
newGame.Platforms.Add(plat);
}
return newGame;
}
}
Unfortunately, I can't make the third parameter an out parameter due to my need to overwrite existing entity data during updating. Again, it's definitely not a pretty, or even good solution, but it does the job. I'm sure the OO gods will smite me at a later date.
I have a many-to-many relationship between photos and tags: A photo can have multiple tags and several photos can share the same tags.
I have a loop that scans the photos in a directory and then adds them to NHibernate. Some tags are added to the photos during that process, e.g. a 2009-tag when the photo is taken in 2009.
The Tag class implements Equals and GetHashCode and uses the Name property as the only signature property. Both Photo and Tag have surrogate keys and are versioned.
I have some code similar to the following:
public void Import() {
...
foreach (var fileName in fileNames) {
var photo = new Photo { FileName = fileName };
AddDefaultTags(_session, photo, fileName);
_session.Save(photo);
}
...
}
private void AddDefaultTags(…) {
...
var tag =_session.CreateCriteria(typeof(Tag))
.Add(Restriction.Eq(“Name”, year.ToString()))
.UniqueResult<Tag>();
if (tag != null) {
photo.AddTag(tag);
} else {
var tag = new Tag { Name = year.ToString()) };
_session.Save(tag);
photo.AddTag(tag);
}
}
My problem is when the tag does not exist, e.g. the first photo of a new year. The AddDefaultTags method checks to see if the tag exists in the database and then creates it and adds it to NHibernate. That works great when adding a single photo but when importing multiple photos in the new year and within the same unit of work it fails since it still doesn’t exist in the database and is added again. When completing the unit of work it fails since it tries to add two entries in the Tags table with the same name...
My question is how to make sure that NHibernate only tries to create a single tag in the database in the above situation. Do I need to maintain a list of newly added tags myself or can I set up the mapping in such a way that it works?
You need to run _session.Flush() if your criteria should not return stale data.
Or you should be able to do it correctly by setting the _session.FlushMode to Auto.
With FlushMode.Auto, the session will automatically be flushed before the criteria is executed.
EDIT: And important! When reading the code you've shown, it does not look like you're using a transaction for your unit of work. I would recommend wrapping your unit of work in a transaction - that is required for FlushMode.Auto to work if you're using NH2.0+ !
Read further here: NHibernate ISession Flush: Where and when to use it, and why?
If you want the new tag to be in the database when you check it each time you need to commit the transaction after you save to put it there.
Another approach would be to read the tags into a collection before you process the photos.
Then like you said you would search local and add new tags as needed. When you are done with the folder you can commit the session.
You should post your mappings as i may not have interpreted your question correctly.
This is that typical "lock something that is not there" problem. I faced it already several times and still do not have a simple solution for it.
This are the options I know until now:
Optimistic: have a unique constraint on the name and let one of the sessions throw on commit. Then you try it again. You have to make sure that you don't end in a infinite loop when another error occurs.
Pessimistic: When you add a new Tag, you lock the whole Tag table using TSQL.
.NET Locking: you synchronize the threads using .NET locks. This only works if you parallel transactions are in the same process.
Create Tags using a own session (see bellow)
Example:
public static Tag CreateTag(string name)
{
try
{
using (ISession session = factors.CreateSession())
{
session.BeginTransaction();
Tag existingTag = session.CreateCriteria(typeof(Tag)) /* .... */
if (existingtag != null) return existingTag;
{
session.Save(new Tag(name));
}
session.Transaction.Commit();
}
}
// catch the unique constraint exception you get
catch (WhatEverException ex)
{
// try again
return CreateTag(name);
}
}
This looks simple, but has some problems. You get always a tag, that is either existing or created (and committed immediately). But the tag you get is from another session, so it is detached for your main session. You need to attach it to your session using cascades (which you probably don't want to) or update.
Creating tags is not coupled to your main transaction anymore, this was the goal but also means that rolling back your transaction leaves all created tags in the database. In other words: creating tags is not part of your transaction anymore.