Serializing entity to XML - add method - asp.net-mvc

Can anybody help me with the below?
Models
public class Integer
{
public int IntegerID { get; set; }
[Required(ErrorMessage = "Enter an integer")]
[Integer(ErrorMessage = "Enter an integer")]
public int IntegerValue { get; set; }
public int IntegerListID { get; set; }
public virtual IntegerList IntegerList { get; set; }
}
public class IntegerList
{
public int IntegerListID { get; set; }
public string Direction { get; set; }
public long Performance { get; set; }
public virtual ICollection<Integer> Integers { get; set; }
public IntegerList()
{
Integers = new List<Integer>();
}
}
Controller Action
public ActionResult XMLexport () {
Object obj = db.IntegerLists.Include("Integers");
Serialize(obj);
return View();
}
public static string Serialize(Object obj)
{
DataContractSerializer serializer = new DataContractSerializer(obj.GetType());
MemoryStream memoryStream = new MemoryStream();
serializer.WriteObject(memoryStream, obj);
return Encoding.UTF8.GetString(memoryStream.GetBuffer());
}
At the line
serializer.WriteObject(memoryStream, obj);
I'm getting the error:
Type 'System.Data.Entity.Infrastructure.DbQuery`1[[IntegerSorter.Models.IntegerList, IntegerSorter, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]' is an invalid collection type since it does not have a valid Add method with parameter of type 'IntegerSorter.Models.IntegerList'.
Can somebody advise me where and how to implement the Add method?
Update:
Changing:
Object obj = db.IntegerLists.Include("Integers");
to
Object obj = db.IntegerLists.Include("Integers").ToList();
results in:
Type 'System.Data.Entity.DynamicProxies.IntegerList_62F0932A6DFC38A25629DF18911498D42B3785A93BCE8B8D2F77C3363B3F4200' with data contract name 'IntegerList_62F0932A6DFC38A25629DF18911498D42B3785A93BCE8B8D2F77C3363B3F4200:http://schemas.datacontract.org/2004/07/System.Data.Entity.DynamicProxies' is not expected. Consider using a DataContractResolver or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.

Try changing this line:
Object obj = db.IntegerLists.Include("Integers");
To this:
Object obj = db.IntegerLists.Include("Integers").ToList();
This will cause the database query to run and give you a List<IntegerList> instead of a DbQuery<IntegerList>. This should then provide what the serializer wants (because it has a Add(IntegerList) method available as requested by the error).

I've accepted Greg's answer but feel I should detail the subsequent issues I had to work through:
Type 'System.Data.Entity.DynamicProxies.IntegerList_62F0932A6DFC38A25629DF18911498D42B3785A93BCE8B8D2F77C3363B3F4200' with data contract name 'IntegerList_62F0932A6DFC38A25629DF18911498D42B3785A93BCE8B8D2F77C3363B3F4200:http://schemas.datacontract.org/2004/07/System.Data.Entity.DynamicProxies' is not expected. Consider using a DataContractResolver or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.
was solved with:
Context.Configuration.ProxyCreationEnabled = false;
and then:
Object graph for type 'System.Collections.Generic.List`1[[IntegerSorter.Models.Integer, IntegerSorter, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]' contains cycles and cannot be serialized if reference tracking is disabled.
was solved by decorating the navigation property on the Integer class as below:
[IgnoreDataMember]
public virtual IntegerList IntegerList { get; set; }

Related

Send an IQueryable of arbitrary type to a general method

The problem: I am trying to create a general method that will take in an IQueryable which can be many different types of data including custom. In this method I will be doing a sort depending on the type of IQueryable that is being passed in.
What I am doing is creating a custom class with the following:
public class sortObject
{
public String OrderParam { get; set; }
public int pageSize { get; set; }
public int pageIndex { get; set; }//This is what page the user is on
public IQueryable<dynamic> entity { get; set; }
}
I will pass in an IQueryable object to this object like so:
sortObject so = new sortObject();
so.entity = _context.userAcount.Select(x=>x);
...
The so.entity will be IQueryable<dynamic> but in the base section of the object (while in debugging) will be of type userAccount. I want the data in the base in order to run the search.
My issue is that I do not know what the IQueryable type is until run time since this is a general method. It can be of type user, or of type address etc, but the sorting will still work because I will pass in what I want to order this by in the sortObject.
How can I either get the base data or convert the IQueryable type at runtime?
I found that this works in the sort table method:
var entity = so.entity.AsQueryable().OrderBy("UserName");
var data = entity.Skip(so.pageSize*(so.pageIndex-1)).Take(so.pageSize);
I think what you want is a solution involving generics - try
public class sortObject<T>
{
public String OrderParam { get; set; }
public int pageSize { get; set; }
public int pageIndex { get; set; }//This is what page the user is on
public IQueryable<T> entity { get; set; }
}
This will allow you to declare a sortObject with an entity of whatever type you want the IQuerable to contain.
You can make your method be something like
public void DoSomething<T>(sortObject<T> input)
{
// input.entity is now of type T
}
and you can call
sortObject so = new sortObject<userAccount>();
so.entity = _context.userAcount.Select(x=>x);
DoSomething(so);

The properties expression is not valid. The expression should represent a property

I have these two entities
public class Song : IPathHavingEntity
{
public int Id { get; set; }
[Required]
public string Path { get; set; }
[Required]
public virtual Album Album { get; set; }
[Required]
public int TrackNumber { get; set; }
}
public class Album : IPathHavingEntity
{
public int Id { get; set; }
[Required]
public string Path { get; set; }
public virtual IEnumerable<Song> Songs { get; set; }
[Required]
public int AlbumNumber { get; set; }
}
Path is defined in the IPathHavingEntity interface.
In my Seed method I want to add a song to the Songs table only if it doesn't exist. For this reason I check that the album path and song path combination don't exist already before adding it thus
context.Songs.AddOrUpdate(
s => new { FilePath = s.Path, AlbumPath = s.Album.Path },
new Song { TrackNumber = 1, Path = "01 Intro.mp3", Album = one });
The problem is I get this error
The properties expression 's => new <>f__AnonymousType0``2(FilePath =
s.Path, AlbumPath = s.Album.Path)' is not valid. The expression should
represent a property: C#: 't => t.MyProperty' VB.Net: 'Function(t) t.MyProperty'. When specifying multiple properties use an anonymous type: C#: 't => new { t.MyProperty1, t.MyProperty2 }' VB.Net: 'Function(t) New With { t.MyProperty1, t.MyProperty2 }'.
What's the problem?
In my case, The Only modification I did that on the Model Classes forget to put {get; set;} with the property declaration, Thus ...It's solved my problem.
Like this:
Before:
public int Supplier_ID;
public String Supplier_Code;
After:
public int Supplier_ID { get; set; }
public String Supplier_Code { get; set; }
Kindly Check your Model Classes should have the Get/Set property
I struggled with a similar issue for several hours today and was finally able to resolve it. I'm not sure if this will work for your situation but it's worth investigating.
The problem may be caused by the Album property of your Song entity being marked as virtual. I'm not an EF expert but I don't think it likes that virtual property when initializing your anonymous type. Add a non-virtual property for the album path (but keep the virtual navigation property), like this:
public class Song : IPathHavingEntity
{
public int Id { get; set; }
[Required]
public string Path { get; set; }
[Required]
public virtual Album Album { get; set; }
public string AlbumPath { get; set; }
[Required]
public int TrackNumber { get; set; }
}
And then perform the AddOrUpdate using that non-virtual property, like this:
context.Songs.AddOrUpdate(
s => new { FilePath = s.Path, AlbumPath = s.AlbumPath },
new Song { TrackNumber = 1, Path = "01 Intro.mp3", Album = one });
EF should then only allow you to add songs where the given song path and album path do not already exist. Whether your Song domain object can have a non-virtual AlbumPath property is another question but this should at least allow you to run your seed method in the way you described.
EF does not create a column for a property which does not have either getters or setters. For example, EF will not create columns for the following City and Age properties.
using System.ComponentModel.DataAnnotations;
public class Student
{
private int _age = 0;
public int StudentId { get; set; }
public string StudentName { get; set; }
public string City { get{ return StudentName;} }
public int Age { set{ _age = value;} }
}
Referance : https://www.entityframeworktutorial.net/code-first/notmapped-dataannotations-attribute-in-code-first.aspx
In my case, changing the following values in the mapper worked.
From:
this.HasKey(t => new { FirstName = t.FirstName, LastName = t.LastName });
To:
this.HasKey(t => new { t.FirstName, t.LastName });
What has not been mentioned in any of other answers is that the source of the problem in any case shown is the same: The "custom identification expression" passed in as a parameter of the AddOrUpdate method has to be a valid property of the entity being inserted or updated. Also, it will not accept ComplextType.Property there.
For example:
context.Songs.AddOrUpdate(
s => new { k.Path, k.AlbumPath },
new Song { TrackNumber = 1, Path = "01 Intro.mp3", Album = one });
Note that the problem was resolved when the AlbumPath was used and also note that the anonymous type requires no other fields to be created. Instead, you just need to specify the property names.
It worth mentioning to be careful when using AddOrUpdate as the result can be destructive.

Saving many to many relationship tables in Asp.Net MVC

I use Asp.Net MVC, Entity Framework. I have a form it looks like below.
Here, dropdownlist is filled from a table(types). Checkboxes is filled from another table(test). Tables are like below:
public class Types
{
public int TypesID{get;set;}
public string TestName { get; set; }
public string TestExplanation { get; set; }
public int TestTime { get; set; }
}
public class Tests
{
public int TestID{get;set;
public string Name { get; set; }
public string Code { get; set; }
}
public class Types_Tests
{
public int Types_TestsID{ get; set; }
public int TypesID { get; set; }
public int TestsID { get; set; }
public virtual Types Types { get; set; }
public virtual Tests Tests { get; set; }
}
Types_test table is relation table between Types and Tests. When I click Kaydet button, it shuld save type and checked tests. I made this operation using ViewBag, javascript and hdnvalue.I added checked checkboz values to a hdntext. I made saving process like below:
[HttpPost]
public ActionResult Index(string drpType, string hdntesttypes)
{
var TypeList = Types.GetAll();
ViewBag.TypesList = new SelectList(TypeList, "Id", "Name");
var testypeList = testTypes.GetAll();
ViewBag.TestTypesList = new SelectList(testypeList, "Id", "TestName");
GenericRepository<TestDisabledTypes> testDisabledRepository = new GenericRepository<TestDisabledTypes>(_context);
if (!string.IsNullOrEmpty(hdntesttypes))
{
string[] disabletypesArray = hdntesttypes.Split(',');
using (TransactionScope trns = new TransactionScope())
{
for (int i = 0; i < disabletypesArray.Length; i++)
{
Test_Types types = new Test_Types ();
types.TestTypesID = Convert.ToInt32(disabletypesArray[i]);
types.TypesID = Convert.ToInt32(drpType);
testDisabledRepository.Insert(types);
}
trns.Complete();
}
}
return View();
}
It wokrs. But I search better solution for this process. Can someone give me any idea?
Thanks.
If you don't need additional attributes for your entity class, you don't need create link table.
Just define the following class, and EF will generate the link table for you automatically.
public class Type
{
public int TypesID{get;set;}
public string TestName { get; set; }
public string TestExplanation { get; set; }
public int TestTime { get; set; }
public ICollection<Test> Tests { get; set; }
}
public class Test
{
public int TestID{get;set;
public string Name { get; set; }
public string Code { get; set; }
public ICollection<Type> Types {get;set;}
}
Well, in EntityFramework if you want to create a many to many relation object you need to create new object of "linking" entity. Unfortunately, it is not possible to add first object, add second object and say "Guys, you are in many to many relationships. Are you happy then?" :) You need to create relation object, set appropriate fields in it (I think these are ids of two objects itself) and add it to relation collection (entity) in your model. But before doing so you need to be sure that objects with data you are linking with are already exists in database. Otherwise you'll get an error
Also it's not necessary to create manually transaction because EF does it for you automatically each time you get/save your data

Complex Type Ignored by Entity Framework Code First

Building on Ladislav's answer to
Entity Framework Code First and Collections of Primitive Types
I'm attempting to create a wrapper type EfObservableCollection<T> around an ObservableCollection<T> that has an additional helper property to simplify persistence (certainly this solution has trade-offs, but it's seems workable for my domain).
However, properties of type EfObservableCollection<T> seem to be ignored by EF. No appropriate columns are created in the database. Guessing that implementing IEnumerable<T> might trigger EF to ignore that type, I commented out that implementation with no change in behavior.
What am I missing here?
Entity Class
public class A
{
[DataMember]
public long Id { get; set; }
[DataMember]
public string Text { get; set; }
// Tags is not persisted
[DataMember]
public EfObservableCollection<string> Tags { get; set; }
}
Wrapper Class
[ComplexType]
public class EfObservableCollection<T> : IEnumerable<T>
{
const string VALUE_SEPARATOR = "\x8"; // Backspace character. Unlikely to be actually entered by a user. Assumes ASCII or UTF-8.
readonly string[] VALUE_SEPARATORS = new string[] { VALUE_SEPARATOR };
[NotMapped]
protected ObservableCollection<T> Collection { get; private set; }
public EfObservableCollection()
{
Collection = new ObservableCollection<T>();
}
[DataMember]
public string PersistHelper
{
get
{
string serializedValue = string.Join(VALUE_SEPARATOR, Collection.ToArray());
return serializedValue;
}
set
{
Collection.Clear();
string[] serializedValues = value.Split(VALUE_SEPARATORS, StringSplitOptions.None);
foreach (string serializedValue in serializedValues)
{
Collection.Add((T)Convert.ChangeType(serializedValue, typeof(T))); // T must implement IConvertable, else a runtime exception.
}
}
}
public void Add(T item)
{
Collection.Add(item);
}
IEnumerator<T> GetEnumerator()
{
return Collection.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
It turns out that Entity Framework does not like the generic class EfObservableCollection<T>.
If I derive a non-generic class from that class, data is persisted as expected:
[ComplexType]
public class EfObservableCollectionString : EfObservableCollection<string>
{
}
Joining backspace with list of strings causes cleaning last character in each string item.
I think serialization to json using System.Web.Script.Serialization.JavaScriptSerializer is better.

Using CreateSourceQuery in CTP4 Code First

I'm guessing this is impossible, but I'll throw it out there anyway. Is it possible to use CreateSourceQuery when programming with the EF4 CodeFirst API, in CTP4? I'd like to eagerly load properties attached to a collection of properties, like this:
var sourceQuery = this.CurrentInvoice.PropertyInvoices.CreateSourceQuery();
sourceQuery.Include("Property").ToList();
But of course CreateSourceQuery is defined on EntityCollection<T>, whereas CodeFirst uses plain old ICollection (obviously). Is there some way to convert?
I've gotten the below to work, but it's not quite what I'm looking for. Anyone know how to go from what's below to what's above (code below is from a class that inherits DbContext)?
ObjectSet<Person> OSPeople = base.ObjectContext.CreateObjectSet<Person>();
OSPeople.Include(Pinner => Pinner.Books).ToList();
Thanks!
EDIT: here's my version of the solution posted by zeeshanhirani - who's book by the way is amazing!
dynamic result;
if (invoice.PropertyInvoices is EntityCollection<PropertyInvoice>)
result = (invoices.PropertyInvoices as EntityCollection<PropertyInvoice>).CreateSourceQuery().Yadda.Yadda.Yadda
else
//must be a unit test!
result = invoices.PropertyInvoices;
return result.ToList();
EDIT2:
Ok, I just realized that you can't dispatch extension methods whilst using dynamic. So I guess we're not quite as dynamic as Ruby, but the example above is easily modifiable to comport with this restriction
EDIT3:
As mentioned in zeeshanhirani's blog post, this only works if (and only if) you have change-enabled proxies, which will get created if all of your properties are declared virtual. Here's another version of what the method might look like to use CreateSourceQuery with POCOs
public class Person {
public virtual int ID { get; set; }
public virtual string FName { get; set; }
public virtual string LName { get; set; }
public virtual double Weight { get; set; }
public virtual ICollection<Book> Books { get; set; }
}
public class Book {
public virtual int ID { get; set; }
public virtual string Title { get; set; }
public virtual int Pages { get; set; }
public virtual int OwnerID { get; set; }
public virtual ICollection<Genre> Genres { get; set; }
public virtual Person Owner { get; set; }
}
public class Genre {
public virtual int ID { get; set; }
public virtual string Name { get; set; }
public virtual Genre ParentGenre { get; set; }
public virtual ICollection<Book> Books { get; set; }
}
public class BookContext : DbContext {
public void PrimeBooksCollectionToIncludeGenres(Person P) {
if (P.Books is EntityCollection<Book>)
(P.Books as EntityCollection<Book>).CreateSourceQuery().Include(b => b.Genres).ToList();
}
It is possible to add a method to you derived context that creates a source query for a given navigation on an entity instance. To do this you need to make use of the underlying ObjectContext which includes a relationship manager which exposes underlying entity collections/references for each navigation:
public ObjectQuery<T> CreateNavigationSourceQuery<T>(object entity, string navigationProperty)
{
var ose = this.ObjectContext.ObjectStateManager.GetObjectStateEntry(entity);
var rm = this.ObjectContext.ObjectStateManager.GetRelationshipManager(entity);
var entityType = (EntityType)ose.EntitySet.ElementType;
var navigation = entityType.NavigationProperties[navigationProperty];
var relatedEnd = rm.GetRelatedEnd(navigation.RelationshipType.FullName, navigation.ToEndMember.Name);
return ((dynamic)relatedEnd).CreateSourceQuery();
}
You could get fancy and accept a Func for the navigation property to avoid having to specify the T, but here is how the above function is used:
using (var ctx = new ProductCatalog())
{
var food = ctx.Categories.Find("FOOD");
var foodsCount = ctx.CreateNavigationSourceQuery<Product>(food, "Products").Count();
}
Hope this helps!
~Rowan
It is definately possible to do so. If you have marked you collection property with virtual keyword, then at runtime, you actual concrete type for ICollection would be EntityCollection which supports CreateSourceQuery and all the goodies that comes with the default code generator. Here is how i would do it.
public class Invoice
{
public virtual ICollection PropertyInvoices{get;set}
}
dynamic invoice = this.Invoice;
dynamic invoice = invoice.PropertyInvoices.CreateSourceQuery().Include("Property");
I wrote a blog post on something similar. Just be aware that it is not a good practice to rely on the inner implementation of ICollection getting converted to EntityCollection.
below is the blog post you might find useful
http://weblogs.asp.net/zeeshanhirani/archive/2010/03/24/registering-with-associationchanged-event-on-poco-with-change-tracking-proxy.aspx

Resources