I am not able to serialize nested entities.
This is my transfer object
[ProtoContract]
[Serializable]
[DataContract]
public class MyClassTO
{
[ProtoMember(1)]
[DataMember]
public List<MyEntity> ListOfMyEntities {get;set;};
}
On my backend, I fire the following linq to entities query, fill the transfer object and return it to the client:
var myClassTO = new MyClassTO();
myClassTO.ListOfMyEntities = Context.MyEntity.Include("ReferencedEntity.AnotherReferencedEntity").ToList;
return myClassTO;
The client receives the list of MyEntity objects but included entities are not serialized(they are all null). Does anybody have any idea about it?
Related
I am connecting to a database-first dll using Entity Framework 6.2.0 and I am trying to get the primary key for a given Entity at runtime. I don't know the Entity type until runtime, which is why I'm trying to use reflection to get the primary key.
Using the following, I'm getting the error Mapping and metadata information could not be found for EntityType 'System.Type':
private string GetPrimaryKey<T>(T entity) where T : class
{
Context.DefaultContainerName = EFContainerName;
var ESet = Context.CreateObjectSet<T>().EntitySet;
return ESet.ElementType.KeyMembers.Select(k => k.Name).ToArray().First();
}
I've seen a lot of information on the Mapping and Metadata error, but not with System.Type and so I feel like it may be less of a mapping error and more the way I'm using the Generic Type parameter?
create abstract class like this
public abstract class EntityObject
{
public abstract Guid EntityKey { get; }
}
inherit this class from an entity object
public class Model: EntityObject
{
public Guid Id { get; set; }
public override Guid EntityKey => Id;
}
for use;
var primaryKey = (Model as EntityObject)?.EntityKey;
I am using Spring Boot to implement rest api. There are three entities SeqTb, PairTb, and GroupTb and they are nested. SeqTb has manytoone with PairTb. PairTb has onetomany relationship with SeqTb and also manytoone with GroupTb.
//SeqTb.java
#Entity
#Table(name="SEQ_TB")
public class SeqTb implements Serializable {
.......
#ManyToOne
#JoinColumn(name="PAIR_ID")
private PairTb pairTb;
......
}
// PairTb.java
#Entity
#Table(name="PAIR_TB")
#NamedQuery(name="PairTb.findAll", query="SELECT p FROM PairTb p")
public class PairTb implements Serializable {
#ManyToOne
#JoinColumn(name="GROUP_ID")
private GroupTb groupTb;
#OneToMany(mappedBy="pairTb", cascade=CascadeType.ALL)
private List<SeqTb> seqTbs;
}
//GroupId.java
#Entity
#Table(name="GROUP_TB")
public class GroupTb implements Serializable {
//bi-directional many-to-one association to PairTb
#OneToMany(mappedBy="groupTb", cascade=CascadeType.ALL)
private List<PairTb> pairTbs;
}
In my controller GET request with analysisId was handled in the following way:
#RequestMapping(
value = "/api/seqs/{analysis_id}",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<SeqTb> getSeqByAnalysisId(#PathVariable("analysis_id") String analysis_id) {
SeqTb seq = seqService.findByAnalysisId(analysis_id);
return new ResponseEntity(seq, HttpStatus.OK);
}
I also create a bean class SeqServiceBean that extends the interface SeqService which in turn calls methods from the following JPA repository for query.
//SeqRepository.java
#Repository
public interface SeqRepository extends JpaRepository<SeqTb, Integer> {
#Override
public List<SeqTb> findAll();
public List<SeqTb> findByAnalysisId(String analysisId);
}
When I query a SeqTb object with SeqTb.PairTb == null, the api works just fine. However, if the analysisId I put in the url belongs to a SeqTb record that associates with a pairId which in turn belongs to a groupId, the program would go nuts. Below is the output, the first part output is correct (bold text). After that it keeps printing PairTb and GroupTb in loops (repeating keywords pairTb, groupTb).
{"rowId":8,"analysisId":"cce8d2c2-a6dc-4ee9-ba97-768f058abb50","analyteCode":"D","center":"UCSC",
"pairTb":{"rowId":4,"pairCode":"01ad975d-c2ed-4e4d-bd3b-c9512fc9073c","groupTb":{"rowId":1,"groupName":"PAWG_pilot-50","pairTbs":[{"rowId":1,"pairCode":"00ad0ffe-2105-4829-a495-1c2aceb5bb31","groupTb":{"rowId":1,"groupName":"PAWG_pilot-50","pairTbs":
Meanwhile I got lots of errors from tomcat server:
Caused by: java.lang.IllegalStateException: getOutputStream() has already been called for this response
at org.apache.catalina.connector.Response.getWriter(Response.java:565) ~[tomcat-embed-core-8.0.32.jar:8.0.32]
at org.apache.catalina.connector.ResponseFacade.getWriter(ResponseFacade.java:212) ~[tomcat-embed-core-8.0.32.jar:8.0.32]
How do I ignore the nested entity object inside an entity and get only the meaning columns?
You can also annotate a property with #JsonIgnore in order to not output that field.
Found the solution. Created a value object that only contains the specific columns from entity and leave out the nested entity object. And it works.
I want to have a simple generic Entity interface pretty much like a map such as on client side in a Gwt + GwtQuery project .
public interface Entity extends JsonBuilder {
public String JsonObject getProperty(String property) ;
public Entity setProperty(String name , JsonObject obj ) ;
public String getPropertyType(String property) /* returns the actual
}
I want to be able to convert any pojo on server side to a Map form along with some type info and retrieve it on client as an Entity. Entities can be nested.
Is this doable ?
If yes. Please give some detailed guidelines.
To clarify further my goal is to have a single generic Entity interface that is capable of representing varied/diverse types of pojos from server. The type information of such a dynamic entity is expected to be available on the client side as a separate entity.
Do you think the code below will work and serve my purpose ? If yes - how will the json text underneath look like ?
public interface Tuple extends JsonBuilder {
public JsonValue get(String name);
public void set(String name, JsonValue ser);
}
public interface Entity extends Tuple {
public String getType();
public Tuple[] getTuples();
}
I've got POCO domain entities that are persisted using Entity Framework 5. They are obtained from the DbContext using a repository pattern and are exposed to a RESTful MVC WebApi application through a UoW pattern. The POCO entities are proxies and are lazy loaded.
I am converting my entities to DTOs before sending them to the client. I am using Automapper to do this and it seems to be working fine with Automapper mapping the proxy POCOs to DTOs, keeping the navigation properties intact. I am using the following mapping for this:
Mapper.CreateMap<Client, ClientDto>();
Example of Domain/DTO objects:
[Serializable]
public class Client : IEntity
{
public int Id { get; set; }
[Required, MaxLength(100)]
public virtual string Name { get; set; }
public virtual ICollection<ClientLocation> ClientLocations { get; set; }
public virtual ICollection<ComplianceRequirement> DefaultComplianceRequirements { get; set; }
public virtual ICollection<Note> Notes { get; set; }
}
public class ClientDto : DtoBase
{
public int Id { get; set; }
[Required, MaxLength(100)]
public string Name { get; set; }
public ICollection<ClientLocation> ClientLocations { get; set; }
public ICollection<ComplianceRequirementDto> DefaultComplianceRequirements { get; set; }
public ICollection<Note> Notes { get; set; }
}
Now I am trying to update my context using DTOs sent back up from the wire. I am having specific trouble with getting the navigational properties/related entities working properly. The mapping for this I'm using is:
Mapper.CreateMap<ClientDto, Client>()
.ConstructUsing((Func<ClientDto, Client>)(c => clientUow.Get(c.Id)));
Above, clientUow.Get() refers to DbContext.Set.Find() so that I am getting the tracked proxy POCO object from EF (that contains all of the related entities also as proxies).
In my controller method I am doing the following:
var client = Mapper.Map<ClientDto, Client>(clientDto);
uow.Update(client);
client successfully is mapped, as a proxy POCO object, however it's related entities/navigational properties are replaced with a new (non-proxy) POCO entity with property values copied from the DTO.
Above, uow.Update() basically refers to a function that performs the persist logic which I have as:
_context.Entry<T>(entity).State = System.Data.EntityState.Modified;
_context.SaveChanges();
The above doesn't persist even persist the entity, let alone related ones. I've tried variations on the mappings and different ways to persist using detaching/states but always get "an object with the same key already exists in the ObjectStateManager" exceptions.
I've had a look at countless other threads and just can't get it all working with Automapper. I can grab a proxy object from the context and manually go through properties updating them from the DTO fine, however I am using Automapper to map domain -> DTO and it would be alot more elegant to use it to do the reverse, since my DTOs resemble my domain objects to a large extent.
Is there a textbook way to handle Automapper with EF, with Domain Objects/DTOs that have navigational properties that also need to be updated at the same time?
UPDATE:
var originalEntity = _entities.Find(entity.Id);
_context.Entry<T>(originalEntity).State = System.Data.EntityState.Detached;
_context.Entry<T>(entity).State = System.Data.EntityState.Modified;
The above persistence logic updates the 'root' EF proxy object in the context, however any related entities are not updated. I'm guessing that this is due to them not being mapped to EF proxy objects but rather plain domain objects. Help would be most appreciated!
UPDATE:
It seems that what I'm trying to achieve is not actually possible using the current version of EF(5) and that this is a core limitation of EF and not to do with Automapper:
Link
Link
I guess it's back to doing it manually. Hope this helps someone else who is wondering the same.
You have allready identified the problem:
The above persistence logic updates the 'root' EF proxy object in the
context, however any related entities are not updated
You are setting the modified state on the root node only. You must write code to iterate through all the objects and set the state to modified.
I implemented a pattern to handle this hierarchy model state with EF.
Every entity model class implements an interface like below, as do the view model classes:
public interface IObjectWithState
{
ObjectState ObjectState { get; set; }
}
The ObjectState enumeration is defined below:
public enum ObjectState
{
Unchanged = 0,
Added = 1,
Modified = 2,
Deleted = 3
}
For example when saving a deep hierarchy of objects using EF, I map the view model objects to their equivalent entity objects, including the ObjectState.
I then attach the root entity object to the context (and consequently all child objects):
dbContext.MyCustomEntities.Attach(rootEntityObj);
I then have an extension method on the DbContext that loops through all the items in the context's change tracker and update each entity's state (as you have done above).
public static int ApplyStateChanges(this DbContext context)
{
int count = 0;
foreach (var entry in context.ChangeTracker.Entries<IObjectWithState>())
{
IObjectWithState stateInfo = entry.Entity;
entry.State = ConvertState(stateInfo.ObjectState);
if (stateInfo.ObjectState != ObjectState.Unchanged)
count++;
}
return count;
}
Then we can simply save the changes as normal:
dbContext.SaveChanges();
This way, all the hierarchy of child objects will be updated accordingly in the database.
What you want to do is get the Entity from the database first:
var centity = _context.Client.First(a=>a.Id = id)
Then you map over this and update (this is what you were looking for, it will only map things it finds in the inputDTO, and leave the other properties alone)
Mapper.Map<UpdateClientInput, Client>(inputDto, centity);
_context.update();
I have the following code:
public interface IKeyed<TKey>
{
TKey Id { get; }
}
// This is the entity framework generated model. I have added the
// IKeyed<Guid> interface
public partial class Person : IKeyed<Guid>
{
public Guid Id { get; set; }
}
public class Repository<TKey, TEntity> : IKeyedRepository<TKey, TEntity>
where TEntity : class, IKeyed<TKey>
{
private readonly IObjectSet<TEntity> _objectSet;
public Repository(IOjectSet<TEntity> objectSet)
{
_objectSet = objectSet;
}
public TEntity FindBy(TKey id)
{
return _objectSet.FirstOrDefault(x => x.Id.Equals(id));
}
}
[Update]
Here is how I am calling this:
Db2Entities context = new Db2Entities(_connectionString); // This is the EF context
IObjectSet<Person> objectSet = context.CreateObjectSet<Person>();
IKeyedRepository<Guid, Person> repo = new Repository<Guid, Person>(objectSet);
Guid id = Guid.NewGuid();
Person person = repo.FindBy(id); // This throws the exception.
The above code compiles. When the 'FindBy' method is executed, I get the following error:
Unable to create a constant value of type 'Closure type'. Only primitive types (for instance Int32, String and Guid) are supported in this context.
Since the type of my 'Id' is a Guid (one of the primitive types supported) it seems like I should be able to massage this into working.
Anyone know if this is possible?
Thanks,
Bob
It doesn't work this way. You cannot call Equals because EF doesn't know how to translate it to SQL. When you pass expression to FirstOrDefault it must be always only code which can be translated to SQL. It is probably possible to solve your problem with some manual building of expression tree but I can reference other solutions already discussed on Stack Overflow.
ObjectContext offers method named GetObjectByKey which is exactly what you are trying to do. The problem is that it requires EntityKey as parameter. Here are two answers which show how to use this method and how to get EntityKey:
Entity Framework Simple Generic GetByID but has differents PK Name
generic GetById for complex PK
In your case the code will be less complicated because you know the name of the key property so you generally need only something like this:
public virtual TEntity FindBy(TKey id)
{
// Build entity key
var entityKey = new EntityKey(_entitySetName, "Id", key);
// Query first current state manager and if entity is not found query database!!!
return (TEntity)Context.GetObjectByKey(entityKey);
}
The problem here is that you cannot get entitySetName from IObjectSet so you must either pass it to repository constructor or you must pass ObjectSet.
Just in case you will want to use DbContext API (EFv4.1) in the future instead of ObjectContext API it will be much simplified because DbSet offers Find method:
generic repository EF4 CTP5 getById