exclude id field to copy an object into another object - c#

I want to have a duplicate from an object that field Id must be specified with a database that means I shouldn't define it directly.
I find my object and copy all parameters into another object exclude the id field
but it doesn't look list the best way to copy all fields into another object to exclude just the id field.
I have done it this way but looking for a better way
/*duplicate product*/
products product = db.products.Find(id);
products duplicateProduct = new products {
title = product.title,
stock_count=product.stock_count,
price=product.price,
category_id=product.category_id,
context=product.context,
Featured=product.Featured,
ForSale=product.ForSale,
discount_prcent=product.discount_prcent
};
db.products.Add(duplicateProduct);
db.SaveChanges();
/*End duplicate product*/

Dreaming
If c# 9's record type could be used as Entity Framework object we could do:
var a2 = a1 with { Id = 2 };
Current solution
Copying properties may seem tedious but it's OK. It does the job.
Constructors are preferred to type initialisers { A = a ... because if Products gets a new field existing code will not copy all fields and there will be no compile errors.
AsNoTracking
Maybe following would work:
products product = db.products.AsNoTracking().Find(id);
product.Id = null;
db.products.Add(duplicateProduct);
db.SaveChanges();

Okay, there is more than one solution to this problem. As I said in the comment if you want ID values to always be different from each other when you create a copy of the product you can use Copy Constructor. Here is the code snippet for that:
public class Program
{
public static void Main()
{
Product product= new Product()
{
Property1=1,
Property2=2,
ID=3
};
Product copyProduct=new Product(product);
}
}
public class Product
{
public int Property1 {get;set;}
public int Property2 {get;set;}
public int ID {get;set;}
public Product()
{
}
public Product(Product product)
{
Property1=product.Property1;
Property2=product.Property2;
}
}
But be careful when you are copying reference values. You may want to have a look at this article Shallow copy vs. Deep Copy

Related

c# defer the save implementation

I need assists ;-) to be honest not sure what to call it so if people come up with the more correct wording I will change the title to suit.
I have written a class for 'what ever' the class is like a utility class.. can be used in many projects across the entire app.
In the utility class.. there is a reference to the EF DB Context. This is for when i want to persist the results into the database.
I would like to remove the dependency on this being in the Utility class and rather pass in the save method.
I am struggling to figure out how you would do this. i.e. with c# Action i know you can pass in a method to be preformed i.e a pointer to a function. But how do I let that pointer know about things inside my Utility case.
I hope i worded all that correctly, please assist with either an example or link to what i am on about.
Showing code: not sure its necessary in this case. But here is a crude example.
public class UtilityCase
{
public List<Person> Persons = new List<Person>();
public void AddPerson(string name)
{
Person newPerson = new Person {Name = name};
Persons.Add(newPerson);
if (Persons.Count > 10)
{
PersistClear();
}
}
public void PersistClear()
{
//I want to be able to Set this from outside of the UtilityCase
var context = new Context();
//I want to remove the referance to the Entity (DB) Person
foreach (Person item in Persons)
{
//add person to db
}
context.saveChanges();
Persons.Clear();
}
}
DB entity case
public class Person
{
public string Name { get; set; }
}
So I understand that i would need to create a local class to the Utility to remove the reference to the Person (DB) but how do i get my function to inject to know about things inside the UtilityCase. Thanks
You need something like that?
//doesn't depends on specific Entity Data Model
public class UtilityCase
{
public List<EntityObject> Persons = new List<EntityObject>();
private readonly Action<IEnumerable<EntityObject>> _saveImpl;
public UtilityCase(Action<IEnumerable<EntityObject>> saveImpl)
{
_saveImpl = saveImpl;
}
...
public void PersistClear()
{
_saveImpl(Persons);
}
}
Call it from another project with specific Entity Data model (Context):
UtilityCase uc=new UtilityCase((col) =>
{
//I want to be able to Set this from outside of the UtilityCase
var context = new Context();
//I want to remove the referance to the Entity (DB) Person
foreach (EntityObject item in col)
{
//add person to db
context.Persons.Add((Person)item));
}
context.SaveChanges();
});
PS: not run, may contain minor errors
I am not sure exactly what you are asking but why do you need all this code and why can't you add the Person entity to the collection in Context like
var context = new Context();
context.Persons.Add(new Person {Name = name});
context.SaveChanges();
Not sure why you are maintaining an extra List<Persons> in your code. whatever, code you have shown can actually be done directly using the Persons collection present in your EF Context

EF 6.0 Many to Many Relationships edits

I'm having a problem with my Entity Framework 6.0 my set up is as follows
public Post
{
[Key]
public int Id {get;set;}
public String Name {get;set;}
public virtual List<Category> Categories {get;set;}
}
public Category
{
[Key]
public int Id {get;set;}
public string Name {get;set;}
public virtual List<Post> Posts {get;set;}
}
so the problem arises when I try to modify one of the lists like this
Posts.Categories.Remove(category);
Posts.Categories.Add(newCategory);
entities.SaveChanges();
I get the following exception, and the exception only happens when I try to modify a Post that has already been created and that has categories.
If the foreign-key does not support null values, a new relationship must be defined, the foreign-key property must be assigned another non-null value, or the unrelated object must be deleted.
I'm not too sure what to do in this case, should I delete the Post from the Category as well ??? Keep in mind that by removing the Category from the list I just want to remove it from that collection not to remove the whole object from my DB. Any suggestions ?
This is my first post to StackOverflow if somebody needs more info please let me know.
The way I handle these many to many relationships is as follows: (assuming Post is an object from the DB)
var tmp = Post.Categories.Select(q => q).ToList();
//delete all links
foreach (var lab in tmp) {
Posts.Categories.Remove(lab);
}
db.SaveChanges();
//add new cats
foreach (var lblgroup in myListofNewCats) {
Post.Categories.Add(db.Categories.Single(q => q.ID=something);
}
It works out best when you submit your changes after the delete.
In case there are no changes, or in case you remove and add the same entity again without submitting in between it might throw some errors.
I'm sure there might be better solutions.
You could define your middle table and then just delete the record in that. That way, you would not be deleting the category itself, which it appears that you are doing now. I suggest that you amend your models as follows:
public Post
{
[Key]
public int Id {get;set;}
public String Name {get;set;}
//For the many to 1 relationship
public virtual ICollection <PostCategory> PostCategories{get;set;}
//You wont need this anymore
//public virtual List<Category> Categories {get;set;}
}
and...
public Category
{
[Key]
public int Id {get;set;}
public string Name {get;set;}
//For the many to 1 relationship
public virtual ICollection <PostCategory> PostCategories{get;set;}
//You wont need this anymore
//public virtual List<Post> Posts {get;set;}
}
Now create model for the new table, PostCategory, this will be the middle table. I like to use a single key rather than a double key. You get more flexibility and it is easy to use when using repositories and the out of the box controller delete methods, but you can use a double key if you like - I am not showing that here. In this method, you will need to check for duplicates yourself before adding the record to the database.
public PostCategory
{
[Key]
public int Id {get;set;}
public int PostId {get;set;}
public virtual Post Post {get;set;}
public int CategoryId {get;set;}
public virtual Category Category {get;set;}
}
Remember to define "PostCategories" in your dbcontext as well. (I presume you know how to...?)
Now when you want to delete the link between the Post and the Category, just delete the PostCategory record, like this in your controller:
//Find the record where postId is the PostId and the categoryId is the CategoryId
var postRecord = db.PostCategories.FirstOrDefault(x=>x.PostId==postId && x.CategoryId==categoryId);
if(postRecord!=null)
{
db.PostCategories.Remove(postRecord)
db.SaveChanges();
}
Adding a record is also easy. I do it like this in the controller...
//First create a record to add
PostCategory pc= new PostCategory()
//wire it up... EF adds the Id fields into the record. If you have a problem
// you can even add those.
pc.Category = category;
pc.Post = post;
//add it
db.PostCategories.Add(pc);
db.SaveChanges();
I like this method because now you can save additional stuff in your PostCategory table, such as date of Post etc. I don't like Many to Many relationships, I believe that they will sooner or later be broken down to one to many and many to one... and later when you have to "fix code" - its a pain to say the least. I hope this helps.

Update all objects in a list from objects in another list

I have the following two objects:
public class BlogPost
{
public int BlogPostId { get; set; }
public Author Author { get; set; }
}
public class Author
{
public int AuthorId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
I have two separate lists of 50 Blog Post objects and 50 Author objects. How do I combine the two such that the Author object is assigned to the Blog Post's Author property?
I've tried using the Zip method, but I don't think that's quite what I want. This question is similar, but I want value to be an object from another list.
Context: using the Seed method in EntityFramework to populate my database.
EDIT:
I should have mentioned that, because it is seed data, I don't really care which Author gets matched up to which BlogPost. Hence why I was trying to use the Zip method.
If the BlogPost and Author objects are linked via index you can use a for-loop:
for(int i = 0; i < blogPosts.Count; i++)
blogPosts[i].Author = authors[i];
You could use LINQ approaches like Zip but then you have to create new objects from the old and fill a new list. A for-loop is much more appropriate (and efficient) if you want to modify the original collection. You can also modify only a single property without needing to copy all.
So this works also but is not the best approach (consider that BlogPost had 100 properties):
blogPosts = blogPosts.Zip(authors, (bp, a) => new BlogPost
{
BlogPostId = bp.BlogPostId,
Author = a
}).ToList();
But this requirement brings up the question why you didn't initialized the BlogPost-list correctly in the first place. Why do you need two separate collections at all?
Your blogpost entity needs to maintain a FK AuthorId. When you do, you could have:
public List<BlogPost> Compose(List<BlogPost> blogPosts, List<Author> authors) {
var composedBlogPosts = new List<BlogPost> (blogPosts);
foreach(var blogPost in blogPosts) {
composedBlogPost.Author = authors.Single(a=>a.AuthorId == blogPost.AuthorId);
}
return composedBlogPost;
}

ADO.NET build complex objects using DataReader

I'm trying to create a way to make an unique search into the database and build the right object for my needs. I mean, I use a SQL query that returns me a lot of rows and then I build the collections based on that database rows. E.g.:
We have a table called People and another table called Phones.
Let's suppose that this is my SQL query and will return the following below:
SELECT
P.[Id], P.[Name], PH.[PhoneNumber]
FROM
[dbo].[People] P
INNER JOIN
[dbo].[Phones] PH ON PH.[Person] = P.[Id]
And that's the results returned:
1 NICOLAS (123)123-1234
1 NICOLAS (235)235-2356
So, my class will be:
public interface IModel {
void CastFromReader(IDataReader reader);
}
public class PhoneModel : IModel {
public string PhoneNumber { get; set; }
public PhoneModel() { }
public PhoneModel(IDataReader reader) : this() {
CastFromReader(reader);
}
public void CastFromReader(IDataReader reader) {
PhoneNumber = (string) reader["PhoneNumber"];
}
}
public class PersonModel : IModel {
public int Id { get; set; }
public string Name { get; set; }
public IList<PhoneModel> Phones { get; set; }
public PersonModel() {
Phones = new List<PhoneModel>();
}
public PersonModel(IDataReader reader) : this() {
CastFromReader(reader);
}
public void CastFromReader(IDataReader reader) {
Id = Convert.ToInt32(reader["Id"]);
Name = (string) reader["Name"];
var phone = new PhoneModel();
phone.CastFromReader(reader);
Phones.Add(phone);
// or
Phones.Add(new PhoneModel {
PhoneNumber = (string) reader["PhomeNumber"]
});
}
}
This code will generate a PersonModel object with two phone numbers. That's good so far.
However, I'm struggling to make some good way to deal when I want to manage more tables with this process.
Let's suppose, then, I have a new table called Appointments. It stores the user's appointments to the schedule.
So, adding this table to the query, the result will be:
1 NICOLAS (123)123-1234 17/09/2014
1 NICOLAS (123)123-1234 19/09/2014
1 NICOLAS (123)123-1234 27/09/2014
1 NICOLAS (235)235-2356 17/09/2014
1 NICOLAS (235)235-2356 19/09/2014
1 NICOLAS (235)235-2356 17/09/2014
As you guys can see, the problem is to manage the phones and the appointments this way. Do you can think in anything that could solve this issue?
Thank you all for the opinions!
You cannot transfer your query result to strongly typed objects without first defining these objects' types. If you want to keep query data in memory, I recommend that you transfer it into objects of a previously defined type at some point.
What follows is therefore not something that I would actually recommend doing. But I want to demonstrate to you a possibility. Judge for yourself.
As I suggested in a previous comment, you can mimick strongly typed DTOs using the Dynamic Language Runtime (DLR), which has become available with .NET 4.
Here is an example for a custom DynamicObject type that provides a seemingly strongly-typed façade for a IDataReader.
using System.Data;
using System.Dynamic; // needs assembly references to System.Core & Microsoft.CSharp
using System.Linq;
public static class DataReaderExtensions
{
public static dynamic AsDynamic(this IDataReader reader)
{
return new DynamicDataReader(reader);
}
private sealed class DynamicDataReader : DynamicObject
{
public DynamicDataReader(IDataReader reader)
{
this.reader = reader;
}
private readonly IDataReader reader;
// this method gets called for late-bound member (e.g. property) access
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
int index = reader.GetOrdinal(binder.Name);
result = index >= 0 ? reader.GetValue(index) : null;
return index >= 0;
}
}
}
Then you can use it like this:
using (IDataReader reader = someSqlCommand.ExecuteReader(…))
{
dynamic current = reader.AsDynamic(); // façade representing the current record
while (reader.Read())
{
// the magic will happen in the following two lines:
int id = current.Id; // = reader.GetInt32(reader.GetOrdinal("Id"))
string name = current.Name; // = reader.GetString(reader.GetOrdinal("Name"))
…
}
}
But beware, with this implementation, all you get is a façade for the current record. If you want to keep data of several records in memory, this implementation won't help a lot. For that purpose, you could look into several further possibilities:
Use anonymous objects: cachedRecords.Add(new { current.Id, current.Name });. This is only any good if you access the cachedRecords in the same method where you build it, because the anonymous type used will not be usable outside of the method.
Cache current's data in an ExpandoObject.
If you want to manually write a data type for each combination of columns resulting from your queries, then you have a lot of work to do, and you will end up with lots of very similar, but slightly different classes that are hard to name. Note also that these data types should not be treated as something more than what they are: Data Transfer Objects (DTOs). They are not real domain objects with domain-specific behaviour; they should just contain and transport data, nothing else.
What follows are two suggestions, or ideas. I will only scratch at the surface here and not go into too many details; since you haven't asked a very specific question, I won't provide a very specific answer.
1. A better approach might be to determine what domain entity types you've got (e.g. Person, Appointment) and what domain value types you have (e.g. Phone Number), and then build an object model from that:
struct PhoneNumber { … }
partial interface Person
{
int Id { get; }
string Name { get; }
PhoneNumber PhoneNumber { get; }
}
partial interface Appointment
{
DateTime Date { get; }
Person[] Participants { get; }
}
and then have your database code map to these. If, for example, some query returns a Person Id, Person Name, Phone Number, and an Appointment Date, then each attribute will have to be put into the correct entity type, and they will have to be linked together (e.g. via Participants) correctly. Quite a bit of work. Look into LINQ to SQL, Entity Framework, NHibernate or any other ORM if you don't want to do this manually. If your database model and your domain model are too different, even these tools might not be able to make the translation.
2. If you want to hand-code your data query layer that transforms data into a domain model, you might want to set up your queries in such a way that if they return one attribute A of entity X, and entity X has other attributes B, C, and D, then the query should also return these, such that you can always build a complete domain object from the query result. For example, if a query returned a Person Id and a Person Phone Number, but not the Person Name, you could not build Person objects (as defined above) from the query because the name is missing.
This second suggestion will at least partially save you from having to define lots of very similar DTO types (one per attribute combination). This way, you can have a DTO for a Person record, another for a Phone Number record, another for an Appointment record, perhaps (if needed) another for a combination of Person and Phone Number; but you won't need to distinguish between types such as PersonWithAllAttributes, PersonWithIdButWithoutNameOrPhoneNumber, PersonWithoutIdButWithPhoneNumber, etc. You'll just have Person containing all attributes.

Need to assign object id to field when creating object

I've got an object that has a property which, on creation, should always be populated with the object's id(primary key).
How do I do that?
I've tried assigning the id to the field just after the db savechanges(), before returning to the view, but that creates two records on my db.
Also tried loading a new instance of the same, assign the id to the field and save it, but also creates two records.
Thanks for any help.
//model
public partial class supplier
{
public int id { get; set; }
public int ref { get; set; }
}
//controller
public ActionResult Create(supplier sup)
{
if (ModelState.IsValid)
{
db.suppliers.add(sup)
db.SaveChanges();
sup.ref = sup.id;
db.SaveChanges();
}
...
}
Hi all, thanks for all your help... I've found a solution... don't really know if it's the correct one, but it does the job.
For whoever is interested here it is:
supplier needToUpdateSupplier = (from s in db.suppliers where s.id.Equals(supplier.id) select s).ToList().FirstOrDefault();
if (needToUpdateSupplier != null)
{
needToUpdateSupplier.ref = supplier.id;
db.suppliers.Attach(needToUpdateSupplier);
db.Entry(needToUpdateSupplier).Property(e => e.ref).IsModified = true;
db.SaveChanges();
}
Create the object
Save it (SaveChanges). This will give you the id.
Assign the id to your property, using the existing object (you don't need to load it again)
Save again
Notes: The property must be nullable, because up on creation it will be empty.
// A Test object
class MyObject
{
public int ID {set;get;}
public int? MyProperty {set;get;}
}
void Foo()
{
var test = new MyObject();
db.MyObjects.Add(test);
db.SaveChanges();
// at this moment test has the Id set. You can assign it.
test.MyProperty = test.Id;
db.SaveChanges();
}
With EF it should set the ID for you:
db.Posts.Add(post);
db.SaveChanges();
// post.ID should be now set

Categories

Resources