Circular reference when trying to serialize database - c#

I'm trying to serialize a whole bunch of information with a lot of linked tables so I can pass it through a web service and call it with ajax. The problem I'm having is that there are some one to many relationships, and some many to many relationships and as I'm new to this I'm not sure how to stop the json following infinite loops through my database.
Is there something I am missing a script ignore on something or should I be trying to find a completely different solution?
I need all the data in PageData
public class SiteData
{
public SiteData()
{
this.UrlResponse = new List<Response>();
}
public SiteData(string url, string robots, string siteMap, bool googleVerification, bool bingVerification, List<Response> urlResponse)
{
this.DomainUrl = url;
this.Robots = robots;
this.Sitemap = siteMap;
this.GoogleVerification = googleVerification;
this.BingVerification = bingVerification;
this.UrlResponse = urlResponse;
}
public SiteData(string url)
{
// TODO: Complete member initialization
this.DomainUrl = url;
}
[Key]
public int Id { get; set; }
[Required]
public string DomainUrl { get; set; }
public string Robots { get; set; }
public string Sitemap { get; set; }
public bool GoogleVerification { get; set; }
public bool BingVerification { get; set; }
public List<Response> UrlResponse { get; set; }
[ScriptIgnore]
public virtual ICollection<PageData> PageDatas { get; set; }
}
public class PageData
{
[Key]
[Required]
public int Id { get; set; }
[Required]
public string PageUrl { get; set; }
public string Analytics { get; set; }
public bool Paginated { get; set; }
public bool Flash { get; set; }
public bool Iframe { get; set; }
public bool NoIndexFollow { get; set; }
public bool SchemaTag { get; set; }
public virtual ICollection<Platform> Platforms { get; set; }
public virtual ICollection<AltTag> AltTags { get; set; }
public virtual ICollection<Canonical> Canonicals { get; set; }
public virtual ICollection<MetaTitle> MetaTitles { get; set; }
public virtual ICollection<MetaDesc> MetaDescs { get; set; }
public virtual ICollection<BlogLocation> BlogLocations { get; set; }
public virtual ICollection<H1> H1s { get; set; }
public virtual ICollection<H2> H2s { get; set; }
public virtual ICollection<H3> H3s { get; set; }
public virtual ICollection<ViewState> ViewStates { get; set; }
//[ForeignKey("DomainUrl")]
public SiteData DomainUrl { get; set; }
//public virtual ICollection<SiteData> SiteData { get; set; }
}
public class Platform
{
public Platform() { }
[Key]
public int KeyId { get; set; }
public string PlatformExtension { get; set; }
public int ResponseCode { get; set; }
[ForeignKey("PageData")]
public int Id { get; set; }
[ScriptIgnore]
public virtual PageData PageData { get; set; }
}
public class AltTag
{
public AltTag() { }
public AltTag(int id, string altTag)
{
this.Id = id;
this.AltTagString = altTag;
}
[Key]
public int KeyId { get; set; }
public string AltTagString { get; set; }
[ForeignKey("PageData")]
public int Id { get; set; }
[ScriptIgnore]
public virtual PageData PageData { get; set; }
}
public class Canonical
{
public Canonical() { }
public Canonical(int id, string altTag)
{
this.Id = id;
this.CanonicalString = altTag;
}
[Key]
public int KeyId { get; set; }
public string CanonicalString { get; set; }
[ForeignKey("PageData")]
public int Id { get; set; }
[ScriptIgnore]
public virtual PageData PageData { get; set; }
}
public class MetaTitle
{
public MetaTitle() { }
public MetaTitle(int id, string metaTitle)
{
this.Id = id;
this.MetaTitleString = metaTitle;
}
[Key]
public int KeyId { get; set; }
public string MetaTitleString { get; set; }
[ForeignKey("PageData")]
public int Id { get; set; }
[ScriptIgnore]
public virtual PageData PageData { get; set; }
}
public class MetaDesc
{
public MetaDesc() { }
public MetaDesc(int id, string metaDesc)
{
this.Id = id;
this.MetaDescString = metaDesc;
}
[Key]
public int KeyId { get; set; }
public string MetaDescString { get; set; }
[ForeignKey("PageData")]
public int Id { get; set; }
[ScriptIgnore]
public virtual PageData PageData { get; set; }
}
public class BlogLocation
{
public BlogLocation() { }
public BlogLocation(int id, string blog)
{
this.Id = id;
this.BlogLoc = blog;
}
[Key]
public int KeyId { get; set; }
public string BlogLoc { get; set; }
[ForeignKey("PageData")]
public int Id { get; set; }
[ScriptIgnore]
public virtual PageData PageData { get; set; }
}
public class H1
{
public H1() { }
public H1(int id, string h1)
{
this.Id = id;
this.H1String = h1;
}
[Key]
public int KeyId { get; set; }
public string H1String { get; set; }
[ForeignKey("PageData")]
public int Id { get; set; }
[ScriptIgnore]
public virtual PageData PageData { get; set; }
}
public class H2
{
public H2() { }
public H2(int id, string h2)
{
this.Id = id;
this.H2String = h2;
}
[Key]
public int KeyId { get; set; }
public string H2String { get; set; }
[ForeignKey("PageData")]
public int Id { get; set; }
[ScriptIgnore]
public virtual PageData PageData { get; set; }
}
public class H3
{
public H3() { }
public H3(int id, string h3)
{
this.Id = id;
this.H3String = h3;
}
[Key]
public int KeyId { get; set; }
public string H3String { get; set; }
[ForeignKey("PageData")]
public int Id { get; set; }
[ScriptIgnore]
public virtual PageData PageData { get; set; }
}
public class ViewState
{
public ViewState()
{
this.Existance = new bool();
}
[Key]
public int KeyId { get; set; }
public bool Existance { get; set; }
public int Size { get; set; }
[ForeignKey("PageData")]
public int Id { get; set; }
[ScriptIgnore]
public virtual PageData PageData { get; set; }
}
The actual call:
[WebMethod]
public string GetPage(string pageId)
{
using (var db = new DataContext())
{
PageData page = db.PageDatas.Find(Int32.Parse(pageId));
string json = null;
JavaScriptSerializer jss = new JavaScriptSerializer();
json = jss.Serialize(page);
return json;
}
}

A database is just how you store your information. It has not much to do with how you present that information to the user.
There's no need to make things any more complex than they have to be. What do you show the user? Probably just grids and detail pages, maybe input forms, right?
So provide ways to read only the data you need to show, and to only update the data you need to update.
Here's an example: say you have a grid that you must fill up with data. Rather than fetch data with relationships etc., just fetch a list of rows and bind that list to the grid. One easy way to do this with Entity Framework is to create a VIEW in the database containing only those fields you want to show, then map that VIEW to an Entity in Entity Framework, and then querying that Entity. Grids are read-only anyway (editable grids are completely unnecessary and often very confusing for end users) and you simplify data retrieval this way.
Similarly, for detail pages and even input forms you can provide VIEWs that only contain the data you need to show. For filling up drop-down lists in input forms you can simply read the required entity's values with a simple query.
See also the following links:
Entity Framework and SQL Server View
http://social.msdn.microsoft.com/Forums/en-US/5d834520-8643-4ada-955a-8173178880f4/generate-views-in-entity-framework-50-code-first
http://blogs.u2u.be/diederik/post/2011/01/31/Building-an-Entity-Framework-40-model-on-views-practical-tips.aspx
Good luck!

Related

dotnet mvc relationships in post method

I have these tables: Sales, product, stock and salesProduct. I'm using a database first approach, they were created using EF scaffold. Sales table looks like this:
public partial class Sales
{
public Sales()
{
SalesProduct = new HashSet<SalesProduct>();
}
public int Id { get; set; }
public DateTime? CreationDate { get; set; }
public bool IndActive { get; set; }
public virtual ICollection<SalesProduct> SalesProduct { get; set; }
}
}
I need the post method on sales creation to create a SalesProduct object and add it to the database. I also need it to update the stock of that specific product.
Here are the other tables:
public partial class SalesProduct
{
public int Id { get; set; }
public int SaleId { get; set; }
public int ProductId { get; set; }
public decimal? Value { get; set; }
public bool IndActive { get; set; }
public virtual Produto IdProductNavigation { get; set; } = null!;
public virtual Vendum IdSalesNavigation { get; set; } = null!;
}
}
public partial class Stock
{
public int Id { get; set; }
public int IdProduct { get; set; }
public int? Quantitu { get; set; }
public bool IndActive { get; set; }
public virtual Product IdProductNavigation { get; set; } = null!;
}
}
How can i do that? I'm confused on how to deal with entity relationships in http methods!

Accessing Nested Collection View JSON data

I have a nested JSON data to be accessed. The data is structured into nested data which i want to have into one.
I modeled the JSON response into c# model classes
public class Customer1
{
public string district { get; set; }
public string feeder { get; set; }
public string feeder_code { get; set; }
public string transformer { get; set; }
public string dss_code { get; set; }
public string database_match { get; set; }
public string accountnumber { get; set; }
public string meterno { get; set; }
public TransactionalDetails transactional_details { get; set; }
}
public class Customer2
{
public string accountNumber { get; set; }
public string meterNumber { get; set; }
public string phoneNumber { get; set; }
public int billedAmount { get; set; }
public object billedDate { get; set; }
public string lastPayDate { get; set; }
public Lastpayment lastpayment { get; set; }
}
public class Lastpayment
{
public string transactionRef { get; set; }
public int units { get; set; }
public string transactionDate { get; set; }
public string transactionId { get; set; }
public int transactionBookId { get; set; }
public int amountPaid { get; set; }
public int mscPaid { get; set; }
public string invoiceNumber { get; set; }
}
public class Queryresult
{
public string responseMessage { get; set; }
public Customer1 customer1 { get; set; }
public int responseCode { get; set; }
public string status { get; set; }
}
public class Result
{
public ObservableCollection<Customer1> Customer1 { get; set; }
public int row_count { get; set; }
}
public class Root
{
public bool error { get; set; }
public Result result { get; set; }
}
public class TransactionalDetails
{
public Queryresult queryresult { get; set; }
public bool status { get; set; }
}
I also created the following code to access the data using the root.
var data = JsonConvert.DeserializeObject<root>(readTask);
ObservableCollection<Customer1> innerData2 = data.result.Customer1;
My challenge is that i want to have Customer1, Customer2 and last payment data merged into a single collection view.
with what i have done, i can only access customer1 data. how can i access all into a single collection?

Access data in JSON C# Dynamic variable

I am working with processing/consuming some data from: https://ashesescalation-api-tachyon.stardock.net/v1/products/2641/leaderboards/ladder/de5bfc9a-9092-4014-b52e-89151de42646?offset=0&count=2 (which can be opened easily in Firefox to view.)
I am able to access the data in C# by doing this:
data being the json data...
dynamic players = JArray.Parse(data);
var p = players[0];
Console.Write(p.personaName);
However I am having trouble accessing the part in the JSON data: "dataInteger" for example the "totalUnitsKilled."
p.dataInteger[0].totalUnitsKilled
That "p.dataInteger[0].totalUnitsKilled" doesn't work.
How can I access that data in C#?
Thank you very much for your help.
Warren
See image in visual studio 1
See image in visual studio 2
Kinldy take a look at my comment in your question, base on that link you need to use JsonProperty to mapped the key that has special characters and manually named it based on your needs.
Anyways, you can do the following to achieved what you need.
Copy your link to http://json2csharp.com/
Copy the generated Quicktypes and paste it to your code.
Use JsonProperty to indicate attributes on your properties for the names and manually rename properties that contains invalid_name
And DeserializeObject the object.
Here is the code:
Declare the classes from the generated quicktypes.
public class DataInteger
{
[JsonProperty(PropertyName = "totalUnitsKilled ")]
public int totalUnitsKilled { get; set; }
public int totalTitansKilled { get; set; }
public int totalTimePlayed { get; set; }
[JsonProperty(PropertyName = "substrate-TotalGamesPlayed")]
public int SubstrateTotalGamesPlayed { get; set; }
[JsonProperty(PropertyName = "phC-TotalGamesPlayed")]
public int PHCTotalGamesPlayed { get; set; }
public int lastReplayVersion { get; set; }
public int replayUploadedCount { get; set; }
}
public class RootObject
{
public string personaLadderId { get; set; }
public int rank { get; set; }
public string personaId { get; set; }
public string personaName { get; set; }
public string avatarUrl { get; set; }
public string avatarUrlSmall { get; set; }
public string avatarUrlMedium { get; set; }
public string avatarUrlLarge { get; set; }
public string ladderType { get; set; }
public string ladderId { get; set; }
public string seasonId { get; set; }
public int bracketId { get; set; }
public string bracketName { get; set; }
public int rankingScore { get; set; }
public int secondaryScore { get; set; }
public int ruleTypeId { get; set; }
public int wins { get; set; }
public int losses { get; set; }
public int ties { get; set; }
public int tieStreak { get; set; }
public int winStreak { get; set; }
public int lossStreak { get; set; }
public int longestTieStreak { get; set; }
public int longestWinStreak { get; set; }
public int longestLossStreak { get; set; }
public int bracketMaxScore { get; set; }
public int bracketScore { get; set; }
public DateTime updateDate { get; set; }
public int totalMatchesPlayed { get; set; }
public DataInteger dataInteger { get; set; }
}
Call the API (Magic begins here)
var httpClient = new HttpClient();
var link = $#"https://ashesescalation-api-tachyon.stardock.net/v1/products/2641/leaderboards/ladder/de5bfc9a-9092-4014-b52e-89151de42646?offset=0&count=2";
var response = await httpClient.GetAsync(link);
var contents = await response.Content.ReadAsStringAsync();
//deserialized json result object...
dynamic json = JsonConvert.DeserializeObject(contents);
foreach (var item in json)
{
//deserialized again the item
var data = JsonConvert.DeserializeObject<RootObject>(Convert.ToString(item));
//you can now access all the properties including dataInteger.
Console.WriteLine(Convert.ToString(data.dataInteger.totalUnitsKilled));
Console.WriteLine(Convert.ToString(data.dataInteger.totalTitansKilled));
}
Update:
If you don't want to use strongly typed class you can do parsing using JArray
JArray jsonVal = JArray.Parse(contents) as JArray;
dynamic items = jsonVal;
foreach (dynamic item in items)
{
var x = item.dataInteger;
//you can access the fields inside dataInteger.
Console.WriteLine(x["totalUnitsKilled "]);
Console.WriteLine(x["phC-TotalGamesPlayed"]);
Console.WriteLine(x["substrate-TotalGamesPlayed"]);
}
Hope this will help you.
As suggested by other users, there is a space in property name "totalUnitsKilled ", if you change it to "totalUnitsKilled". Below code will work fine:-
Console.WriteLine(p.dataInteger.totalUnitsKilled);
Your JSON string is wrong.
[{"personaLadderId":"371eaf1c-4cfe-4873-af41-56e0cb9fcf91","rank":1,"personaId":"55834d01-13f3-445e-861f-0bc4769d87cc","personaName":"Amelie","avatarUrl":"https://steamcdn-a.akamaihd.net/steamcommunity/public/images/avatars/fe/fef49e7fa7e1997310d705b2a6158ff8dc1cdfeb.jpg","avatarUrlSmall":"https://steamcdn-a.akamaihd.net/steamcommunity/public/images/avatars/fe/fef49e7fa7e1997310d705b2a6158ff8dc1cdfeb.jpg","avatarUrlMedium":"https://steamcdn-a.akamaihd.net/steamcommunity/public/images/avatars/fe/fef49e7fa7e1997310d705b2a6158ff8dc1cdfeb_medium.jpg","avatarUrlLarge":"https://steamcdn-a.akamaihd.net/steamcommunity/public/images/avatars/fe/fef49e7fa7e1997310d705b2a6158ff8dc1cdfeb_full.jpg","ladderType":"Ranked","ladderId":"de5bfc9a-9092-4014-b52e-89151de42646","seasonId":"fd7dd807-4ac2-40ec-8476-a4b2937f70af","bracketId":0,"bracketName":"Legendary","rankingScore":38,"secondaryScore":2054,"ruleTypeId":1,"wins":374,"losses":32,"ties":0,"tieStreak":0,"winStreak":8,"lossStreak":0,"longestTieStreak":0,"longestWinStreak":61,"longestLossStreak":3,"bracketMaxScore":0,"bracketScore":0,"updateDate":"2018-03-03T14:13:09.647Z","totalMatchesPlayed":406,"dataInteger":{"totalUnitsKilled ":92615,"totalTitansKilled":14,"totalTimePlayed":294676,"substrate-TotalGamesPlayed":127,"phC-TotalGamesPlayed":6,"lastReplayVersion":265301040,"replayUploadedCount":160}},{"personaLadderId":"f0dd3482-f057-44d6-a626-9c9389ad2583","rank":2,"personaId":"b53815ab-d753-4415-9ea6-03a4519c3222","personaName":"Rebellions","avatarUrl":"https://steamcdn-a.akamaihd.net/steamcommunity/public/images/avatars/b9/b9847c92d44896304cc2d673e1fbe7bc99af7f5b.jpg","avatarUrlSmall":"https://steamcdn-a.akamaihd.net/steamcommunity/public/images/avatars/b9/b9847c92d44896304cc2d673e1fbe7bc99af7f5b.jpg","avatarUrlMedium":"https://steamcdn-a.akamaihd.net/steamcommunity/public/images/avatars/b9/b9847c92d44896304cc2d673e1fbe7bc99af7f5b_medium.jpg","avatarUrlLarge":"https://steamcdn-a.akamaihd.net/steamcommunity/public/images/avatars/b9/b9847c92d44896304cc2d673e1fbe7bc99af7f5b_full.jpg","ladderType":"Ranked","ladderId":"de5bfc9a-9092-4014-b52e-89151de42646","seasonId":"fd7dd807-4ac2-40ec-8476-a4b2937f70af","bracketId":0,"bracketName":"Legendary","rankingScore":38,"secondaryScore":2049,"ruleTypeId":1,"wins":767,"losses":188,"ties":0,"tieStreak":0,"winStreak":3,"lossStreak":0,"longestTieStreak":0,"longestWinStreak":52,"longestLossStreak":6,"bracketMaxScore":0,"bracketScore":0,"updateDate":"2017-10-29T18:03:33.92Z","totalMatchesPlayed":955,"dataInteger":{"totalUnitsKilled ":293274,"totalTitansKilled":88,"totalTimePlayed":924881,"phC-TotalGamesPlayed":4,"substrate-TotalGamesPlayed":350,"lastReplayVersion":250285270,"replayUploadedCount":703}}]
There is a space in your json key name ("totalUnitsKilled ") which is ultimately converted to a variable name.
Correct your JSON key name will fix this issue. There are other keys with error as well.
You can check at http://json2csharp.com/. Wherever it is "invalid_name", key name is wrong.
public class DataInteger
{
public int __invalid_name__totalUnitsKilled { get; set; }
public int totalTitansKilled { get; set; }
public int totalTimePlayed { get; set; }
public int __invalid_name__substrate-TotalGamesPlayed { get; set; }
public int __invalid_name__phC-TotalGamesPlayed { get; set; }
public int lastReplayVersion { get; set; }
public int replayUploadedCount { get; set; }
}
public class RootObject
{
public string personaLadderId { get; set; }
public int rank { get; set; }
public string personaId { get; set; }
public string personaName { get; set; }
public string avatarUrl { get; set; }
public string avatarUrlSmall { get; set; }
public string avatarUrlMedium { get; set; }
public string avatarUrlLarge { get; set; }
public string ladderType { get; set; }
public string ladderId { get; set; }
public string seasonId { get; set; }
public int bracketId { get; set; }
public string bracketName { get; set; }
public int rankingScore { get; set; }
public int secondaryScore { get; set; }
public int ruleTypeId { get; set; }
public int wins { get; set; }
public int losses { get; set; }
public int ties { get; set; }
public int tieStreak { get; set; }
public int winStreak { get; set; }
public int lossStreak { get; set; }
public int longestTieStreak { get; set; }
public int longestWinStreak { get; set; }
public int longestLossStreak { get; set; }
public int bracketMaxScore { get; set; }
public int bracketScore { get; set; }
public DateTime updateDate { get; set; }
public int totalMatchesPlayed { get; set; }
public DataInteger dataInteger { get; set; }
}
You can use JSON.Net attributes to define C# variables related to JSON key names. Check this for more details.
Your new class should look like:
public class DataInteger
{
[JsonProperty(PropertyName = "totalUnitsKilled ")]
public int totalUnitsKilled { get; set; }
public int totalTitansKilled { get; set; }
public int totalTimePlayed { get; set; }
[JsonProperty(PropertyName = "substrate-TotalGamesPlayed")]
public int substrateTotalGamesPlayed { get; set; }
[JsonProperty(PropertyName = "phC-TotalGamesPlayed")]
public int phCTotalGamesPlayed { get; set; }
public int lastReplayVersion { get; set; }
public int replayUploadedCount { get; set; }
}

Reusing models in Web Api

I have a c# class as below
public class CreateStudent
{
public int Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public int Age { get; set; }
}
and I need another class with following properties
public class EditStudent
{
public string Name { get; set; }
public string Address { get; set; }
public int Age { get; set; }
public DateTime Date_of_Birth { get; set; }
}
I have repeated properties except that one field (Date_of_Birth) is added in the EditStudent Model.
Is there an option to reuse some of the properties from previous CreateStudent model
I am going to handle these data as Json objects in my front end angularjs based application
You could do this with a null-able property.
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public int Age { get; set; }
public DateTime? Date_of_Birth { get; set; }
}
This way you only have one Student model that can accommodate both use-cases.
you should be using inheritance feature here.
public class CreateStudent
{
public int Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public int Age { get; set; }
}
public class EditStudent : CreateStudent
{
public DateTime Date_of_Birth { get; set; }
}

Why is my EF detaching not enough?

I try to detach an entity of type group.
Actucally I save it in my cache, and detach it a moment before responding the client.
On the next request I get the group from the cache and re-attch a new objectContext.
However I get An entity object cannot be referenced by multiple instances of IEntityChangeTracker
I know attach includes all related entities but detach doesn't. There I have to detach every related entity.
What am I missing in my detach?
here is my entities hirarchy:
public partial class App
{
public App()
{
this.Pairs = new HashSet<Pair>();
}
public string AppName { get; set; }
public System.Guid AppGuid { get; set; }
public string ClientAppID { get; set; }
public bool IsDeleted { get; set; }
public Nullable<System.DateTime> CreatedDate { get; set; }
public Nullable<System.DateTime> UpdatedDate { get; set; }
public virtual AppsData AppsData { get; set; }
public virtual ICollection<Pair> Pairs { get; set; }
}
public partial class AppsData
{
public System.Guid AppGuid { get; set; }
public string Url { get; set; }
public string DisplayName { get; set; }
public string AppDesc { get; set; }
public string PrivacyPolicyUrl { get; set; }
public string TermsOfUseUrl { get; set; }
public string LocalizationKey { get; set; }
public string Compatibility { get; set; }
public bool HiddenApp { get; set; }
public bool IsExperimental { get; set; }
public virtual App App { get; set; }
}
public partial class Browser
{
public Browser()
{
this.BrowserVersions = new HashSet<BrowserVersion>();
}
public int BrowserID { get; set; }
public string BrowserName { get; set; }
public string BrowserCode { get; set; }
public virtual ICollection<BrowserVersion> BrowserVersions { get; set; }
}
public partial class BrowserVersion
{
public BrowserVersion()
{
this.BrowserVerToCriterias = new HashSet<BrowserVerToCriteria>();
}
public System.Guid BrowserVersionID { get; set; }
public int BrowserID { get; set; }
public string Version { get; set; }
public System.DateTime CreatedDate { get; set; }
public System.DateTime UpdatedDate { get; set; }
public Nullable<int> Group_Id { get; set; }
public virtual Browser Browser { get; set; }
public virtual ICollection<BrowserVerToCriteria> BrowserVerToCriterias { get; set; }
}
public partial class BrowserVerToCriteria
{
public System.Guid CriteriaID { get; set; }
public System.Guid BrowserVersionID { get; set; }
public string ConditionBrowserVersion { get; set; }
public virtual BrowserVersion BrowserVersion { get; set; }
public virtual Criterion Criterion { get; set; }
}
public partial class CommonConfig
{
public int ID { get; set; }
public string NAME { get; set; }
public string VALUE { get; set; }
public System.DateTime CREATED_DATE { get; set; }
public System.DateTime UPDATED_DATE { get; set; }
public byte GROUP_ID { get; set; }
public string DESCRIPTION { get; set; }
}
public partial class Country
{
public Country()
{
this.Criteria = new HashSet<Criterion>();
this.Criteria1 = new HashSet<Criterion>();
}
public int CountryID { get; set; }
public string CountryCode { get; set; }
public string CountryName { get; set; }
public virtual ICollection<Criterion> Criteria { get; set; }
public virtual ICollection<Criterion> Criteria1 { get; set; }
}
public Criterion()
{
this.BrowserVerToCriterias = new HashSet<BrowserVerToCriteria>();
this.Countries = new HashSet<Country>();
this.CountriesExceptions = new HashSet<Country>();
this.Pairs = new HashSet<Pair>();
}
public System.Guid CriteriaID { get; set; }
public string Domains { get; set; }
public System.DateTime CreatedDate { get; set; }
public System.DateTime UpdatedDate { get; set; }
public string DomainsExclude { get; set; }
public virtual ICollection<BrowserVerToCriteria> BrowserVerToCriterias { get; set; }
public virtual ICollection<Country> Countries { get; set; }
public virtual ICollection<Country> CountriesExceptions { get; set; }
public virtual ICollection<Pair> Pairs { get; set; }
}
public partial class CTID
{
public string CTID1 { get; set; }
public string AppVersion { get; set; }
}
public partial class CtidPgPastExistence
{
public string Ctid { get; set; }
}
public partial class Group
{
public Group()
{
this.Pairs = new HashSet<Pair>();
}
public System.Guid GroupId { get; set; }
public int TestId { get; set; }
public int IdInTest { get; set; }
public bool WelcomeExperienceEnabledByDefault { get; set; }
public virtual MamConfiguration MamConfiguration { get; set; }
public virtual ICollection<Pair> Pairs { get; set; }
}
public partial class MamConfiguration
{
public MamConfiguration()
{
this.Groups = new HashSet<Group>();
this.MamConfigurationCTIDs = new HashSet<MamConfigurationCTID>();
}
public int TestID { get; set; }
public string TestName { get; set; }
public string Description { get; set; }
public int StatusId { get; set; }
public System.DateTime CreatedDate { get; set; }
public System.DateTime UpdatedDate { get; set; }
public bool IsProd { get; set; }
public int TestTraffic { get; set; }
public virtual ICollection<Group> Groups { get; set; }
public virtual MamConfigurationStatus MamConfigurationStatus { get; set; }
public virtual ICollection<MamConfigurationCTID> MamConfigurationCTIDs { get; set; }
}
public partial class MamConfigurationCTID
{
public int TestID { get; set; }
public string CTID { get; set; }
public virtual MamConfiguration MamConfiguration { get; set; }
}
public partial class MamConfigurationStatus
{
public MamConfigurationStatus()
{
this.MamConfigurations = new HashSet<MamConfiguration>();
}
public int StatusId { get; set; }
public string Status { get; set; }
public virtual ICollection<MamConfiguration> MamConfigurations { get; set; }
}
public partial class Pair
{
public Pair()
{
this.Groups = new HashSet<Group>();
}
public System.Guid PairID { get; set; }
public System.Guid CriteriaID { get; set; }
public System.Guid AppGuid { get; set; }
public virtual App App { get; set; }
public virtual Criterion Criterion { get; set; }
public virtual ICollection<Group> Groups { get; set; }
}
public partial class SettingsServicesConfig
{
public int ID { get; set; }
public string Name { get; set; }
public string URL { get; set; }
public int Interval { get; set; }
public System.DateTime UPDATED_DATE { get; set; }
public System.DateTime CREATED_DATE { get; set; }
public int GROUP_ID { get; set; }
}
here is my detach function:
public void Detach<T>(MaMDBEntities maMdbEntities, T item) where T : class, new()
{
switch (typeof (T).Name.ToLower())
{
case "group":
{
var group = item as Group;
if (group == null)
{
mApplicationLogger.Error(string.Format("Couldn't cast item to type 'Group'"));
throw new InvalidCastException(string.Format("Couldn't cast item to type 'Group'"));
}
DetachState(maMdbEntities, group.MamConfiguration);
foreach (var pair in group.Pairs.ToList())
{
DetachState(maMdbEntities, pair.App);
DetachState(maMdbEntities, pair.App.AppsData);
foreach (var country in pair.Criterion.Countries.ToList())
{
DetachState(maMdbEntities, country);
}
foreach (var country in pair.Criterion.CountriesExceptions.ToList())
{
DetachState(maMdbEntities, country);
}
foreach (var browserVerToCriterias in pair.Criterion.BrowserVerToCriterias.ToList())
{
DetachState(maMdbEntities, browserVerToCriterias.BrowserVersion.Browser);
DetachState(maMdbEntities, browserVerToCriterias.BrowserVersion);
DetachState(maMdbEntities, browserVerToCriterias);
}
DetachState(maMdbEntities, pair.Criterion);
DetachState(maMdbEntities, pair);
}
break;
}
}
maMdbEntities.Entry(item).State = EntityState.Detached;
}
private static void DetachState(MaMDBEntities maMdbEntities, object item)
{
maMdbEntities.Entry(item).State = EntityState.Detached;
}
I believe that you need to make sure that none of the entities which remain in your context, reference any of those which have been detached. So if say, something else references a detached instance of Pair, the context will quite happily find it, traverse its navigation properties and add the whole lot back in.
Rather than setting the State property have you tried:
((IObjectContextAdapter)maMdbEntities).ObjectContext.Detach(item);
This is supposed to detach any links to the item being detached in addition to the item itself.
EDIT
Ok, lets look at the "detach any links to the item being detached ...", ObjectContext.Detach ultimately calls this method:
// System.Data.Objects.EntityEntry
internal void Detach()
{
base.ValidateState();
bool flag = false;
RelationshipManager relationshipManager = this._wrappedEntity.RelationshipManager;
flag = (base.State != EntityState.Added && this.IsOneEndOfSomeRelationship());
this._cache.TransactionManager.BeginDetaching();
try
{
relationshipManager.DetachEntityFromRelationships(base.State);
}
finally
{
this._cache.TransactionManager.EndDetaching();
}
this.DetachRelationshipsEntries(relationshipManager);
IEntityWrapper wrappedEntity = this._wrappedEntity;
EntityKey entityKey = this._entityKey;
EntityState state = base.State;
if (flag)
{
this.DegradeEntry();
}
else
{
this._wrappedEntity.ObjectStateEntry = null;
this._cache.ChangeState(this, base.State, EntityState.Detached);
}
if (state != EntityState.Added)
{
wrappedEntity.EntityKey = entityKey;
}
}
DetachEntityFromRelationships breaking down all the links.
The documentation on ObjectContext.Detach is not specific about the tearing down of links http://msdn.microsoft.com/en-us/library/system.data.objects.objectcontext.detach.aspx it does say "After the Detach method is called, the system will no longer keep references that point to this object and it can be collected by the garbage collector", which implies all LinkDescriptors will also have been removed.
With regards your 3rd comment "Do you think IObjectContextAdapter will enable full detachment. Or there will always be other object in context that I will misss and not detach?" there are two things here; there is the property of the object and the LinkDescriptor which the context uses to track to the relationship. Detach merely stops tracking an object's relationships by detaching the LinkDescriptors, it doesn't detach the object at the other end of the relationship. Neither does it set such properties to null, if you inspect the object after detaching it will still have those properties set.
Is this the best approach? Detaching and reattaching is difficult to get right. If you need to detach and reattach I would suggest you move your deep detach rountines into the classes themselves rather than in a generic method.
That said, you wrote "On the next request I get the group from the cache..." which leads to me wonder what would be the longest period of time between two requests? Could you be introducing concurrency issues by caching? Are you hosting your WCF service in IIS? Could you use IIS's caching if concurrency will not be a problem? Are you handling all requests on the same thread? You might not be aware that ObjectContext instance methods are not thread safe.

Categories

Resources