Serialize .net linq object to json, exception on datacontext - c#

I'd like to serialize my linq object to json.
The linq object is disconnected, meaning the datacontext was disposed long time ago.
There are "related" objects which were not loaded during the object load process which can't be accessed (When accessed, runtime error return "Cannot access a disposed object." because the datacontext is gone)
Is there any json/xml converter with the ability to serialize this object?
I don't want to chanage the dbml
Is there any serialization object with the ability to configure ignore exception properties or so?
To reproduce that issue, create this object:
public class HelpMeToSerialize
{
public string Name;
public int Age
{
get
{
throw new Exception("Can't access this on runtime");
}
set
{
}
}
}
And simply serialize it with this code or any other code you have:
HelpMeToSerialize obj = new HelpMeToSerialize();
System.Xml.Serialization.XmlSerializer x = new System.Xml.Serialization.XmlSerializer(obj.GetType());
x.Serialize(Console.Out, obj);

If your Linq generated object has a relationship to another table, which you did not load at the time of creating the object (via Linq2Sql for example), then you can do the following to serialize it:
//assume that your linq created object with class type StronglyTypedLinqObject has a field, ID, and a relationship called RelatedThing
StronglyTypedLinqObject row_from_db = null;
using(var myDatabase = new MyLinqContext(ConnectionString))
{
myDatabase.DeferredLoadingEnabled = false;
//assume this pulls one item back which has a relationship
row_from_db = (from o in myDatabase.TheTableToSelectFrom select o).Single();
row_from_db.RelatedThing = null; //this line may be unnecessary
} // context is disposed now
return Json(row_from_db); //this call should succeed
If you disable deferred loading and try to serialize then it won't try to lazy load the related objects.
Hope that works.
Mustafa

The DataContractSerializer for XML and DataContractJsonSerializer for JSON. You could also try the NewtonSoft JSON library.

Related

XML deserialize brings back empty list

I have a dictionary of abilityobjects <id, abilityObj> that I'm trying to serialize in XML. Because you can't XML Serialize a dictionary, I change it into a list on serialization
public class BattleSerializable : TyrantSerializable
{
[XmlIgnoreAttribute]
[NonSerialized]
[DoNotSerialize]
public Dictionary<int, AbilityObjectSerializable> battleObjects;
public List<AbilityObjectSerializable> serializedBattleObjects
{
get
{
if (battleObjects == null)
{
battleObjects = new Dictionary<int, AbilityObjectSerializable>();
}
return battleObjects.Select(x => x.Value).ToList();
}
set
{
battleObjects = value.ToDictionary(x => x.entityId, x => x);
}
}
It serializes correctly. I.e. the XML that gets saved makes sense
<BattleSerializable>
...
<serializedBattleObjects>
<AbilityObjectSerializable xmlns:d3p1="http://www.w3.org/2001/XMLSchema-instance" d3p1:type="FireballObject">
<hexDirection>southeast</hexDirection>
<gridX>0</gridX>
<gridZ>7</gridZ>
<entityId>3</entityId>
<lastAnimation>STATUE</lastAnimation>
<timer>0</timer>
<abilityPos>2</abilityPos>
<abilityType>FIREBALL</abilityType>
<health>100</health>
<tilesPerTurn>2</tilesPerTurn>
<jump>1</jump>
<fall>99</fall>
<damage>5</damage>
<lineTraversed>
<xDisplace>1</xDisplace>
<zDisplace>-2</zDisplace>
<endTileFacing>east</endTileFacing>
</lineTraversed>
<moveDirection>
<xDisplace>1</xDisplace>
<zDisplace>-2</zDisplace>
<endTileFacing>east</endTileFacing>
</moveDirection>
</AbilityObjectSerializable>
</serializedBattleObjects>
</BattleSerializable>
But when I try to then -load- this XML and turn it into actual C# objects, this list comes in empty for some reason, causing the app to blow up.
What am I missing? All the other lists in this class serialize/deserialize correctly.
My load code:
public BattleSerializable Load(string path)
{
var serializer = new XmlSerializer(typeof(BattleSerializable));
try
{
using (var stream = new FileStream(path, FileMode.Open))
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(stream);
string xmlString = xmlDoc.InnerXml;
BattleSerializable bs = (BattleSerializable)this.LoadFromXML(xmlString);
return bs;
}
}
catch (Exception e)
{
throw new SettingLoadException("Settings failed validation");
}
}
The way a lot of serializers work is by calling Add on a list, only actually assigning anything back to the setter if the serializer created the list (perhaps because it was null, or fixed size such as an array). So imagine the serializer doing:
var list = obj.SomeProperty;
while (moreOfTheSame)
list.Add(ReadOneOfThose());
It never calls the setter, so any logic in there: irrelevant. You'll probably need a custom list type here, or perhaps more simply: have a nice simple POCO/DTO model that just maps to the serialization shape with no fun logic, and project between this model and your domain model separately to serialization.

Update detached objects in EF that already exist in object state manager

I'm hoping this will be an easy one but for the life of me, I cannot find the specific answer elsewhere on SO or any other site.
I have a basic repository/unit of work pattern with Entity Framework Code First. It all works smoothly except for certain cases of Update. THe problem is I have a set of Entity Framework model objects, all prefixed with "Db" which EF returns, but I then convert them to plain DataContract Model objects to pass to the Web layer to give separation of concerns. I have a basic conversion interface that just populates a WebModel object from the DataModel object, copying field by field verbatim.
So if you retrieve a DbUser object from EF with ID of 1, then convert to a User object, then convert that BACK to a DbUser object, you end up with a DbUser with ID of 1, but it is a DIFFERENT object to the one you started with, though they have the same primary key field, the actual CLR objects themselves are different.
The following works
User user;
using (var work = new UnitOfWork())
{
var repository = new UserDataRepository(work);
user = repository.Get(1);
repository.save();
}
var modelUser = DataConverter.Convert(user);
modelUser.Name = "new name";
user = BusinessConverter.Convert(modelUser);
using (var work = new UnitOfWork())
{
var repository = new UserDataRepository(work);
repository.Update(user);
repository.save();
}
As they are using two different unit of works/contexts, so the second block has nothing in the ObjectStateManager to compare to and can just attach the detached object in the Update() methods
This, however does NOT work
using (var work = new UnitOfWork())
{
var repository = new UserDataRepository(work);
user = repository.Get(1);
repository.save();
var modelUser = DataConverter.Convert(user);
modelUser.Name = "new name";
user = BusinessConverter.Convert(modelUser)
repository.Update(user);
repository.save();
}
NOTE: I know logically this doesn't make much sense to convert and just convert back but go with it, I've simplified the example greatly to make it easier to put into paper, in my actual code there is a reason for doing it that way.
I get the usual error "an object with the same key already exists in the objectstatemanager...". I'm assuming because the Get() loads the object into EF and then the update sees that the object is detached, then tries to attach it and it already exists.
My Update method in my repository is as below
public override bool UpdateItem(DbUser item)
{
if (Work.Context.Entry(item).State == EntityState.Detached)
Work.Context.Users.Attach(item);
Work.Context.Entry(item).State = EntityState.Modified;
return Work.Context.Entry(item).GetValidationResult().IsValid;
}
I made this Extension method to the DbContext to ReAttach the Entity without problems try it out:
public static void ReAttach<T>(this DbContext context, T entity) where T : class
{
var objContext = ((IObjectContextAdapter) context).ObjectContext;
var objSet = objContext.CreateObjectSet<T>();
var entityKey = objContext.CreateEntityKey(objSet.EntitySet.Name, entity);
Object foundEntity;
var exists = objContext.TryGetObjectByKey(entityKey, out foundEntity);
// Detach it here to prevent side-effects
if (exists)
{
objContext.Detach(foundEntity);
}
context.Set<T>().Attach(entity);
}
Then just update your method :
public override bool UpdateItem(DbUser item)
{
Work.Context.ReAttach(item);
Work.Context.Entry(item).State = EntityState.Modified;
return Work.Context.Entry(item).GetValidationResult().IsValid;
}
You might get a manged Entity, and again verbatim map the new DbUser's properties to the managed Object:
public override bool UpdateItem(DbUser item)
{
using (var work = new UnitOfWork())
{
var repository = new UserDataRepository(work);
DbUser managedUser = repository.Get(item.PK);
//foreach DbUser property map the item to managedUser
managedUser.field1 = item.field1;
[..]
repository.Update(managedUser);
repository.Save();
}
}
If you set your context to AsNoTracking() this will stop aspmvc tracking the changes to the entity in memory (which is what you want anyway on the web).
_dbContext.Products.AsNoTracking().Find(id);
I would recommend you read more about this at http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/advanced-entity-framework-scenarios-for-an-mvc-web-application
Yash

Json.Encode(Model) throws "The ObjectContext instance has been disposed" exception

I have a simple razor view:
<script>var fieldList = #Html.Raw(Json.Encode(Model));</script>
This line throws The ObjectContext instance has been disposed exception. If I remove it all works fine even when I use Model later in View.
foreach (SomeCustomObject pField in Model)
{
<div>
#pField.SomeProperty
</div>
}
Controller action
ActionResult SomeAction()
{
List<SomeCustomObject> tList = new List<SomeCustomObject>();
using(EFEntities db = new EFEntities())
{
tList = db.SomeCustomObject.ToList();
}
return View(tList);
}
I presume, that it could be because object has navigation properties that no longer work. Is it possible to tell Json.Encode to use only NON navigation preperties of object?
You can't operate on model obejct outside of using block, where it is loaded. Possibly, JSON.encode does deep reflection analysis of model object and so touches some context-dependent attributes.
So, in common case, you should convert model to JSON in controller/action method, inside using block, put it to string variable and then use this variable in template.
Simplest way that I came up with was:
Create view ViewSomeCustomObjects in database, what returns all fields of SomeCustomObjects table.
Update model from database and include new view.
Use entity what is maped to view instead of table, as this is only for data display.
I REALY hope that if I change SomeCustomObjects table in database, changes will cascade trough entire solution...
Disable lazy loading on the context first with context.Configuration.LazyLoadingEnabled = false; before you start pulling stuff out of your database.
using (var context = new SomeEntityContext())
{
context.Configuration.LazyLoadingEnabled = false; // This is the fixer.
return context.SomeEntitiesWithRelations.ToList();
}

Manage/Update Records in ASP.NET With Redis using ServiceStack

I'm coming from a SQL Server background, and experimenting with Redis in .NET using ServiceStack. I don't mean for Redis to be a full replacement for SQL Server, but I just wanted to get a basic idea of how to use it so I could see where we might make good use of it.
I'm struggling with what I think is a pretty basic issue. We have a list of items that are maintained in a couple of different data stores. For the sake of simplicity, assume the definition of the item is basic: an integer id and a string name. I'm trying to do the following:
Store an item
Retrieve an item if we only know its id
Overwrite an existing item if we only know its id
Show all the items for that specific type
And here's some of the code I've put together:
public class DocumentRepositoryRedis
{
private static string DOCUMENT_ID_KEY_BASE = "document::id::";
public IQueryable<Document> GetAllDocuments()
{
IEnumerable<Document> documentsFromRedis;
using (var documents = new RedisClient("localhost").As<Document>())
{
documentsFromRedis = documents.GetAll();
}
return documentsFromRedis.AsQueryable();
}
public Document GetDocument(int id)
{
Document document = null;
using (var redisDocuments = new RedisClient("localhost").As<Document>())
{
var documentKey = GetKeyByID(document.ID);
if (documentKey != null)
document = redisDocuments.GetValue(documentKey);
}
return document;
}
public void SaveDocument(Document document)
{
using (var redisDocuments = new RedisClient("localhost").As<Document>())
{
var documentKey = GetKeyByID(document.ID);
redisDocuments.SetEntry(documentKey, document);
}
}
private string GetKeyByID(int id)
{
return DOCUMENT_ID_KEY_BASE + id.ToString();
}
}
It all seems to work - except for GetAllDocuments. That's returning 0 documents, regardless of how many documents I have stored. What am I doing wrong?
The typed Redis client also gives you access to the non-typed methods - since Redis ultimately doesn't know or care about your object types. So when you use the client.SetEntry() method, it bypasses some of the typed client's features and just stores the object by a key. You'll want to use the client.Store method since it goes ahead and creates a SET in Redis with all the object IDs related to your type. This SET is important because it's what the GetAll method relies on to serve back all the objects to you. The client.Store method does infer the ID automatically so you'll want to play around with it.
You'd change your GetDocument(int id) and SaveDocument(Document document) methods to use the client.GetById(string id) method, and you'd use client.Store(T value) method. You won't need your GetKeyByID() method anymore. I believe your Document object will need an "Id" property for the typed client to infer your object ID.

update object created in another datacontext

I need your help very much. I'd like to update object created in another datacontext;
Here is my code. Insert statement works well but I can't write code for update
var dataContext = new ReconNewDataContext();
if (Id == 0)
{
var item = this;
dataContext.RequestIO.InsertOnSubmit(item);
dataContext.SubmitChanges();
Id = item.Id;
}
else
{
var item = this;
//update object
}
I've read
Linq2SQL: Update object not created in datacontext
I've tried to use .Attach(this) .Attach(this,true) .Attach(this, oldObjectFromBase) but always I've an errors.
I know I can get object from database and manually transfer data from modified object, but there will be new fields. It means that I must always append these new fields in Save() method.
Is there any "beautiful" method to update object created in another datacontext?
Check out this article: http://omaralzabir.com/linq_to_sql__how_to_attach_object_to_a_different_data_context/
Also, in your example, for update, try doing:
var item = new ObjectBeingUpdated();
//copy over properties from old object to new object, make sure pk's match
//Attach this new object
Something similar worked for my coworker I believe.
UPDATE: Check this out for more info about attach: http://blogs.msdn.com/b/dinesh.kulkarni/archive/2007/10/08/attach-if-you-have-something-detached.aspx
You could use the following pattern:
Fetch existing object from repository
Use AutoMapper to copy properties
Save your object back.

Categories

Resources