Disable Lazy Load EF6 DBFirst at .NET Framework - c#

In my webapi2 application I used db first generation and I created a partial class of context to set both ProxyCreationEnabledand LazyLoadingEnabled to false.
But when I use db.ExameViaAereaOssea.Where(e => e.ConsultaId == model.ConsultaId).ToList() the relation property Consulta is loaded too.
That not happing when I use db.ExameViaAereaOssea.AsNoTracking().Where(e => e.ConsultaId == consultaId).ToList()
I don't want use AsNoTracking for every query
Here are my two classes
public partial class ExameViaAereaOssea
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public ExameViaAereaOssea()
{
}
public int ExameViaAereaOsseaId { get; set; }
public Nullable<int> ConsultaId { get; set; }
public string VAOE125 { get; set; }
public string VAOE250 { get; set; }
public string VAOE500 { get; set; }
public string VAOE750 { get; set; }
public string VAOE1000 { get; set; }
public string VAOE1500 { get; set; }
public string VAOE2000 { get; set; }
public string VAOE3000 { get; set; }
public string VAOE4000 { get; set; }
public string VAOE6000 { get; set; }
public string VAOE8000 { get; set; }
public string VOOE500 { get; set; }
public string VOOE750 { get; set; }
public string VOOE1000 { get; set; }
public string VOOE2000 { get; set; }
public string VOOE3000 { get; set; }
public string VOOE4000 { get; set; }
public string TipoAudiometria { get; set; }
public virtual Consulta Consulta { get; set; }
}
public partial class Consulta
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Consulta()
{
this.ExameViaAereaOssea = new HashSet<ExameViaAereaOssea>();
}
public int ConsultaId { get; set; }
public DateTime? Data {get;set;}
public Nullable<int> PacienteId { get; set; }
public Nullable<int> TipoConsultaId { get; set; }
public Nullable<int> PacienteDadosProfissionaisId { get; set; }
public Nullable<int> ClienteId { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<ExameViaAereaOssea> ExameViaAereaOssea { get; set; }
}
And here is the usage.
public class RegraConsulta(){
public ExamesConsulta BuscaExamesConsulta(Consulta model) {
using (var db = new winmedEntities(false))
{
var retorno = new ExamesConsulta();
retorno.DataConsulta = RetornaDataConsulta(db, model.ConsultaId);
retorno.exAereaOssea = db.ExameViaAereaOssea.Where(c => c.ConsultaId == model.ConsultaId).ToList();
return retorno;
}
}
public DateTime RetornaDataConsulta(winmedEntities db, int consultaId)
{
var consulta = db.Consulta.Find(consultaId);
if (consulta == null)
throw new RegraNegocioException("Consulta não encontrada");
return consulta.Data.Value;
}
}
The return is used in Web Api Controller and return method used like return Ok(new RegraConsulta().BuscaExamesConsulta(new Consulta { ConsultaId = 1 }));

Related

Automapper missing type map configuration

I can't seem to figure out what is going wrong here, I have configured AutoMapper as follows
services.AddAutoMapper(typeof(MetingenView), typeof(Meting));
And in the controller like this:
public MetingenController(IMapper mapper)
{
this._mapper = mapper;
}
After, I use it like this:
var entity = await this.Context.MetingenView.AsNoTracking().FirstOrDefaultAsync(g =>g.IdMeting == key);
if (entity == null)
{
return NotFound();
}
data.Patch(entity);
var meting = await this.Context.Meting.FirstOrDefaultAsync(m => m.IdMeting == key);
this._mapper.Map(entity, meting);
Then the error rolls out:
AutoMapper.AutoMapperMappingException: Missing type map configuration
or unsupported mapping.
EDIT:
Here are the Meting, and MetingenView classes:
public partial class Meting
{
public int IdMeting { get; set; }
public int IdKoeling { get; set; }
public int IdWerknemer { get; set; }
public int IdGebouw { get; set; }
public int Temperatuur { get; set; }
public DateTime AfgenomenTijd { get; set; }
public string ProductNaam { get; set; }
public string Actie { get; set; }
public DateTime? DatumOntstaan { get; set; }
public DateTime? DatumMutatie { get; set; }
public int IndVerwijderd { get; set; }
public DateTime? DatumVerwijderd { get; set; }
public virtual Gebouw IdGebouwNavigation { get; set; }
public virtual Koeling IdKoelingNavigation { get; set; }
public virtual Werknemer IdWerknemerNavigation { get; set; }
}
public partial class MetingenView
{
[Key]
public int IdKlant { get; set; }
public string Locatie { get; set; }
public string SoortKoeling { get; set; }
public int IdMeting { get; set; }
public int IdKoeling { get; set; }
public int IdWerknemer { get; set; }
public int IdGebouw { get; set; }
public int Temperatuur { get; set; }
public string Actie { get; set; }
public string ProductNaam { get; set; }
public DateTime AfgenomenTijd { get; set; }
}
I think the mapping between Meting and MetingenView is not configured in AutoMapper. If you use Asp.Net Core, you could create a profile.
public class MetingProfile : Profile
{
public MetingProfile()
{
CreateMap<MetingenView, Meting>();
}
}
This would create a default mapping that two types have the same property. If you want to config property mapping manually, Function ForMember() would be used.
For example, if you wish that the property MetingenView.IdGebouw maps Meting.IndVerwijderd, you can code this:
CreateMap<MetingenView, Meting>()
.ForMember(dest=>dest.IdGebouw, opt=>opt.MapFrom(src=>src.IndVerwijderd));

E.F Core does not return all values When Include another table

public IEnumerable<Parties> GetAll()
{
return database.Parties;
}
Works very well and the output is:
But when I Include another table by foreignkey like this:
public IEnumerable<Parties> GetAll()
{
return database.Parties.Include(i=>i.User);
}
It does not work, it returns first value of the table and nothing else,the output is :
Users.cs :
public partial class Users
{
public Users()
{
Parties = new HashSet<Parties>();
PartyParticipants = new HashSet<PartyParticipants>();
}
public int Id { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public string Username { get; set; }
public string Email { get; set; }
public string Avatar { get; set; }
public string Biography { get; set; }
public string Password { get; set; }
public virtual ICollection<Parties> Parties { get; set; }
public virtual ICollection<PartyParticipants> PartyParticipants { get; set; }
}
Parties.cs :
public partial class Parties
{
public Parties()
{
Image = new HashSet<Image>();
PartyParticipants = new HashSet<PartyParticipants>();
}
public int Id { get; set; }
public string Name { get; set; }
public DateTime PartyDate { get; set; }
public DateTime CreatedDate { get; set; }
public int ParticipantCount { get; set; }
public int MaxParticipant { get; set; }
public string PartySplash { get; set; }
public string ShortDescription { get; set; }
public string Description { get; set; }
public double Latitude { get; set; }
public double Longitude { get; set; }
public bool EntranceFree { get; set; }
public int? FreeParticipant { get; set; }
public int? FreeParticipantMax { get; set; }
public int UserId { get; set; }
public virtual Users User { get; set; }
public virtual ICollection<Image> Image { get; set; }
public virtual ICollection<PartyParticipants> PartyParticipants { get; set; }
}
As you can see on the 2nd picture it interrupts at first row of the table.
I have added this answer based on Vidmantas's comment. ReferenceLoopHandling should be ignored like this in startup.cs:
services.AddMvc()
.AddJsonOptions(options =>
{
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
});

Creating Viewmodels and mapping to entities

I am creating ViewModels for my entities. The FirmViewModel contains two list collections called Addressess and Websites. I have also created viewmodels for Addresses and Websites. At the moment in the controller code, I am getting trouble assigning Addresses and Wesbite collections
of the Firm Entity to FirmViewModels Addresses and Websites collection. Its says cant cast it implicitly. This is the line in the controller that it complains Addresses = firm.Addresses; How do aassign
Systems.Collections.Generic.ICollection<Manager.Model.Address> to Systems.Collections.Generic.ICollection<Manager.WebUI.ViewModels.AddressViewModel>
NewFirmViewModel
public class NewFirmViewModel
{
public int FirmId { get; set; }
public string FirmName { get; set;}
public Nullable<DateTime> DateFounded { get; set; }
public ICollection<AddressViewModel> Addresses { get; set; }
public ICollection<WebsiteViewModel> Websites { get; set; }
public bool hasIntralinks { get; set; }
}
AddressViewModel
public class AddressViewModel
{
public int AddressId { get; set; }
public string Line1 { get; set; }
public string Line2 { get; set; }
public string Line3 { get; set; }
public string Phone { get; set; }
public bool IsHeadOffice { get; set; }
public int FirmId { get; set; }
}
WebsiteViewModel
public class WebsiteViewModel
{
private int FirmWebsiteId { get; set; }
private string WebsiteUrl { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public int FirmId { get; set; }
}
Entities - Firm
public class FIRM: Entity,IHasAUMs<FIRM_AUM>
{
public FIRM()
{
//this.FIRM_PERSON = new HashSet<FIRM_PERSON>();
this.MANAGERSTRATEGies = new HashSet<MANAGERSTRATEGY>();
this.FIRM_ACTIVITY = new HashSet<FIRM_ACTIVITY>();
this.FIRM_AUMs = new HashSet<FIRM_AUM>();
this.FIRM_REGISTRATION = new HashSet<FIRM_REGISTRATION>();
//this.ACTIVITies = new HashSet<ACTIVITY>();
Addresses = new HashSet<ADDRESS>();
//People = new HashSet<PERSON>();
// Websites = new HashSet<FIRM_WEBSITE>();
}
//public decimal ID { get; set; }
//
//
//
//
public string NAME { get; set; }
public string SHORT_NAME { get; set; }
public string ALTERNATE_NAME { get; set; }
public string WEBSITE { get; set; }
public string WEBSITE_USERNAME { get; set; }
public string WEBSITE_PASSWORD { get; set; }
public bool? INTRALINKS_FIRM { get; set; }
public string NOTES_TEXT { get; set; }
public string NOTES_HTML { get; set; }
public string HISTORY_TEXT { get; set; }
public string HISTORY_HTML { get; set; }
public string HISTORY_SUM_TEXT { get; set; }
public string HISTORY_SUM_HTML { get; set; }
public Nullable<decimal> OLD_ORG_REF { get; set; }
public Nullable<decimal> SOURCE_ID { get; set; }
[DisplayFormat(DataFormatString = PermalConstants.DateFormat)]
public Nullable<DateTime> DATE_FOUNDED { get; set; }
public virtual ICollection<ADDRESS> Addresses { get; set; }
// public ICollection<FIRM_WEBSITE> Websites { get; set; }
// public ICollection<PERSON> People { get; set; }
//public SOURCE SOURCE { get; set; }
// public ICollection<FIRM_PERSON> FIRM_PERSON { get; set; }
public ICollection<MANAGERSTRATEGY> MANAGERSTRATEGies { get; set; }
public ICollection<FIRM_ACTIVITY> FIRM_ACTIVITY { get; set; }
public ICollection<FIRM_REGISTRATION> FIRM_REGISTRATION { get; set; }
//public ICollection<ACTIVITY> ACTIVITies { get; set; }
public ICollection<FIRM_WEBSITE> Websites { get; set; }
public Nullable<int> KEY_CONTACT_ID { get; set; }
[NotMapped]
public ICollection<FIRM_AUM> AUMs
{
get
{
return this.FIRM_AUMs;
}
}
public ICollection<FIRM_AUM> FIRM_AUMs { get; set; }
}
ADDRESS
public class ADDRESS : Entity
{
public ADDRESS()
{
// DATE_CREATED = DateTime.Now;
}
public string LINE1 { get; set; }
public string LINE2 { get; set; }
public string LINE3 { get; set; }
public int CITY_ID { get; set; }
public string POSTAL_CODE { get; set; }
public string SWITCHBOARD_INT { get; set; }
public string NOTES { get; set; }
public int? OLD_ADDRESS_REF { get; set; }
public int? SOURCE_ID { get; set; }
public int FIRM_ID { get; set; }
[ForeignKey("FIRM_ID")]
public FIRM FIRM { get; set; }
[ForeignKey("CITY_ID")]
public CITY City { get; set; }
public ICollection<PERSON> People { get; set; }
// public SOURCE SOURCE { get; set; }
public bool IS_HEAD_OFFICE { get; set; }
[NotMapped]
public string AddressBlurb
{
get
{
return string.Join(",", new[] { LINE1, LINE2, City != null ? City.NAME : "", City != null && City.Country != null ? City.Country.NAME : "" }.Where(x => !string.IsNullOrEmpty(x)));
}
}
}
FIRM_WEBSITE
public class FIRM_WEBSITE : Entity
{
public FIRM_WEBSITE()
{
}
private string _WEBSITE_URL;
public string WEBSITE_URL
{
get
{
if (string.IsNullOrEmpty(_WEBSITE_URL))
return _WEBSITE_URL;
try
{
var ubuilder = new System.UriBuilder(_WEBSITE_URL ?? "");
return ubuilder.Uri.AbsoluteUri;
}
catch (UriFormatException ex)
{
return _WEBSITE_URL;
}
}
set { _WEBSITE_URL = value; }
}
public string USERNAME { get; set; }
public string PASSWORD { get; set; }
public int FIRM_ID { get; set; }
[ForeignKey("FIRM_ID")]
public FIRM FIRM { get; set; }
}
FirmController
public class FirmController : ApiControllerBase
{
[HttpGet]
[Route("api/Firm/{id}")]
public IHttpActionResult Details(int id)
{
var viewModel = GetFirmViewModel(id);
return Ok(viewModel);
}
private NewFirmViewModel GetFirmViewModel(int id)
{
var firmSvc = GetService<FIRM>();
var firm = firmSvc.GetWithIncludes(id, f => f.Addresses, f => f.Websites);
var firmVm = new NewFirmViewModel()
{
FirmId = firm.ID,
FirmName = firm.NAME,
DateFounded = firm.DATE_FOUNDED,
Addresses = firm.Addresses;
};
}
public virtual T GetWithIncludes(int id, params Expression<Func<T, object>>[] paths)
{
try
{
using (new TimedLogger(_perfLogger, GetCompletedText("GetWithIncludes"), typeof(T).Name))
{
return Authorize(_repo.GetWithIncludes(id, paths), AuthAccessLevel.Read);
}
}
catch (Exception ex) { Log(ex); throw; }
}

Bind IEnumerable to ViewModel in C# MVC

I have a table in my view that a model is typed to it. However, now I need to change that model to a ViewModel (so I can Union other models on to it but one step at a time). Currently, I query my model (which works) but now I need to figure out how to convert that IEnumerable to bind it to the ViewModel (in this case, it is searchResultViewModel). I gathered what i would need to loop through each line in the IEnumerable and bind it individually (that is what the foreach loop is, me trying that) but I need to convert it back in to an 'IEnumerable'. How do I bind the IEnumerable to my ViewModel but as an 'IEnumerable'? I cannot find anyone else asking a question like this.
[HttpPost]
public ActionResult SearchResult(SearchOrders searchOrders)
{
var orderList = uni.Orders;
var model = from order in orderList
select order;
if (searchOrders.SearchStartDate.HasValue)
{
model = model.Where(o => o.OrderDate >= searchOrders.SearchStartDate);
}
if (searchOrders.SearchEndDate.HasValue)
{
model = model.Where(o => o.OrderDate <= searchOrders.SearchEndDate);
}
if (searchOrders.SearchAmount.HasValue)
{
model = model.Where(o => o.Total == searchOrders.SearchAmount);
}
var searchResultViewModel = new SearchResultViewModel();
foreach (var record in model)
{
searchResultViewModel.OrderNumber = record.OrderId;
searchResultViewModel.PaymentName = record.PaymentFullName;
searchResultViewModel.OrderDate = record.OrderDate;
searchResultViewModel.Amount = record.Total;
}
return View(model);
}
Here is my SearchOrders Model:
namespace MicrositeInfo.WebUI.Models
{
public class SearchOrders
{
public DateTime? SearchStartDate { get; set; }
public DateTime? SearchEndDate { get; set; }
public decimal? SearchAmount { get; set; }
}
}
and here is my SearchResultViewModel:
namespace MicrositeInfo.WebUI.Models
{
public class SearchResultViewModel
{
public int OrderNumber { get; set; }
public string PaymentName { get; set; }
public DateTime OrderDate { get; set; }
public decimal Amount { get; set; }
}
}
and the model that is being queried is the order model:
namespace MicrositeInfo.Model
{
[Table("Order")]
public class Order
{
public int OrderId { get; set; }
public string SelectedSession { get; set; }
public string StudentCity { get; set; }
public string StudentExtension { get; set; }
public string StudentFullName { get; set; }
public string StudentPhone { get; set; }
public string StudentPin { get; set; }
public string StudentState { get; set; }
public string StudentStreet01 { get; set; }
public string StudentStreet02 { get; set; }
public string StudentUniversityId { get; set; }
public string StudentZip { get; set; }
public string PaymentCity { get; set; }
public string PaymentCreditCardExpiration { get; set; }
public string PaymentCreditCardNumber { get; set; }
public string PaymentCreditCardSecurityCode { get; set; }
[Display(Name="Payment Name")]
public string PaymentFullName { get; set; }
public string PaymentState { get; set; }
public string PaymentStreet01 { get; set; }
public string PaymentStreet02 { get; set; }
public string PaymentZip { get; set; }
[Display(Name = "Package Id")]
[ForeignKey("Product")]
public int ProductId { get; set; }
public virtual Product Product { get; set; }
public decimal Price { get; set; }
public decimal Tax { get; set; }
public decimal Total { get; set; }
[Display(Name = "Order Date")]
public DateTime OrderDate { get; set; }
public string OrderIp { get; set; }
public string StudentEmail { get; set; }
public string PaymentId { get; set; }
public int Status { get; set; }
public string ApprovalCode { get; set; }
public decimal Shipping { get; set; }
public string STCITrackingClassCode { 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