Linq To Entities 5 re-use Expression<TEntity, TResult> in another entity - entity-framework

I've been trying to find this, but I've not had luck. Say I have a database with 2 tables, person and address.
table person
id int
name varchar(50)
addressId int
table address
id int
street varchar(50)
country varchar(50)
In my data layer, I have a business object for Address, which is exposed to external callers. I found an expression that I could use to centralize my creation code at the SQL level. This way I don't have to write:
db.Address.Select( x => new Biz.Address{ street = x.street} ).ToList(); //and all the other properties etc
everywhere. Instead I can now do:
db.Address.Select(AddressDto.ToDto).ToList();
Using this code:
internal static class AddressDto
{
internal static readonly Expression<Func<Address, Biz.Address>> ToDto =
src => new Biz.Address
{
Id = src.id,
Street = src.street,
Country = src.country
};
}
The problem is now that I am trying to do the same thing for the Person object, and I want to re-use this method to fill in the address. However I can't seem to utilize an expression in it.
class Person
{
int Id;
string Name;
Address address;
}
internal static class PersonDto
{
internal static readonly Expression<Func<Person, Biz.Person>> ToDto =
src => new Biz.Person
{
Id = src.id,
Name = src.name,
address = src.Address //How do i set this to an expression?
};
}
The reason I ask for the expression, is because while it compiles fine if I use a normal method, it blows up at runtime, because it can't translate that to the object store. However, if I do:
address = AddressDto.ToDto(src.Address)
the compiler rejects that, as it wants a method, delegate, or event. I'd love to find a way to do this. the idea I'm trying to implement is to basically centralize the code that maps the Entity to the business object, so that my other code is kept clean and maintenance is easier when the schema changes. If there is a different method signature I have to create and maintain, that'd be fine, as I'd place it in the same file and live with it. I just can't seem to find the magic combination that'll make this work.
Thanks!
Update from khan's suggestion.
That just moves this to a linq to objects area. I am trying to do this in the SQL end because of how some queries are built up, we don't want to call .ToList till later.
if I do:
internal static class PersonDto
{
internal static readonly Func<Person, Biz.Person> ToDto =
src => new Biz.Person
{
Id = src.id,
Name = src.name,
address = new Biz.Address { id = src.Address.Id }
};
}
Then that works. i just want to replace the new call.

The compiler doesn't like AddressDto.ToDto because you're passing in an Func<> wrapped in an Expression<> when it is just expecting a Func<>
address = AddressDto.ToDto(src.Address)
Remove the Expression from the signatures and see if it works:
internal static class AddressDto
{
internal static readonly Func<Address, Biz.Address> ToDto =
src => new Biz.Address
{
Id = src.id,
Street = src.street,
Country = src.country
};
}
internal static class PersonDto
{
internal static readonly Func<Person, Biz.Person> ToDto =
src => new Biz.Person
{
Id = src.id,
Name = src.name,
address = AddressDto.ToDto(src.Address)
};
}

Related

Should I enforce referential integrity between my related aggregate roots? If so, where?

This seems like a fundamental question and I have not worked much with DDD. The context of this question is in regards to working with the ABP Framework, its layers, and its generated code.
Should I enforce referential integrity between my related aggregate roots? If so, where?
After using ABP Suite to generate my initial entities, many of which are aggregate roots (AR), I began to implement the navigation properties between them. My initial approach was to modify the constructors of each entity/AR to include the Guid IDs of the dependent entities/ARs.
Original Approach
public Address(Guid id, string name, AddressTypes addressType,
string line1, string line2, string line3,
string city, string postalCode,
Guid stateId, Guid countryId, // <-- dependent AR IDs
bool primary = false, bool active = true)
{
//other properties set
StateId = stateId;
CountryId = countryId;
//etc
}
I got my domain data seed logic working along with my data seed contributors and then I moved on to working on the test data.
Very quickly I realized that I was going to have to create each of the dependent entities/ARs and pass their IDs to the constructors of each entity under test.
That sent me on a search through the documentation for an example or best practice. One thing I came across is this statement from the Entity Best Practices & Conventions page:
Do always reference to other aggregate roots by Id. Never add navigation properties to other aggregate roots.
Okay. So that would seem to suggest that I should have nullable ID properties in my principal/parent AR for each of my dependent/child ARs. Fully managed entities under the AR might be free to have navigation properties, but not the ARs.
Because I want to manage the AR relationships at a higher level, it seems to follow that I should remove the dependent ARs from my constructor or at least make them nullable.
Revised Approach 1
public Address(Guid id, string name, AddressTypes addressType,
string line1, string line2, string line3,
string city, string postalCode,
Guid? stateId = null, Guid? countryId = null, // <-- nullable dependent AR IDs
bool primary = false, bool active = true)
{
//other properties set
StateId = stateId;
CountryId = countryId;
//etc
}
Revised Approach 2
public Address(Guid id, string name, AddressTypes addressType,
string line1, string line2, string line3,
string city, string postalCode,
bool primary = false, bool active = true)
{
//other properties set, not setting dependent IDs
}
Obviously Revised Approach 2 would require the application service to set the dependent ID properties after constructing the object:
Address address = null;
address = await _addressRepository.InsertAsync(new Address
(
id: _guidGenerator.Create(),
name: "DEMO Contact Home Address",
addressType: AddressTypes.Home,
line1: "123 Main St",
line2: "",
line3: "",
city: "Anytown",
postalCode: "00000",
primary: true,
active: true
), autoSave: true);
address.StateId = alState.Id; // set here
address.CountryId = usId; // and here
Am I on track so far?
So, if I want to enforce referential integrity, I should not do that through Entity Framework (or the ORM of choice). I should enforce referential integrity at the Application Service layer instead.
[Authorize(MyProductPermissions.Addresses.Create)]
public virtual async Task<AddressDto> CreateAsync(AddressCreateDto input)
{
if (input.StateId == default)
{
throw new UserFriendlyException(L["The {0} field is required.", L["State"]]);
}
if (input.CountryId == default)
{
throw new UserFriendlyException(L["The {0} field is required.", L["Country"]]);
}
var address = ObjectMapper.Map<AddressCreateDto, Address>(input);
address.TenantId = CurrentTenant.Id;
// BEGIN Referential Integrity Logic
// Assumes that the dependent IDs will be set when the DTO is mapped to the entity
if (address.StateId == null)
{
// log and throw 500 error
}
if (address.CountryId == null)
{
// log and throw 500 error
}
// END Referential Integrity Logic
address = await _addressRepository.InsertAsync(address, autoSave: true);
return ObjectMapper.Map<Address, AddressDto>(address);
}
Is this a correct understanding?
If my dependent IDs are nullable, I can continue to use the ABP Suite generated test code.
await _addressRepository.InsertAsync(new Address
(
Guid.Parse("ca846f1a-8bbd-4e2c-afbd-8e40a03ae18f"),
"7d7b348e410d48ee89e1807beb2f2ac0bd66af4ea82943ec8eee3a52962577b1",
default,
"de5ec0226aba4c1a837c9716b21af6551d10436756724d4fa507028eaaddcdadec779bea0ef04922992f9d2432068b180e6fe95f425f47c68559c1dbd4360fdb",
"53bc12edeb4544158147f3b835b0c4ce5e581844f5c248d69647d80d398706f5ee1c769e4ee14bd0a1e776a369a96ea3c0582b659ce342bdbdf40e6668f3b9f9",
"117880188dfd4a6f96892fea3e62a16f057748ebe76b4dd0a4402918e2fee9055272ff81c53d4c28825cc20d01918386864efd54e1aa458bb449a1d12b349d40",
"866a81007219411a971be2133bf4b5882d4ef612722a45ac91420e0b30d774ed",
"93bba338449444f5",
true,
true
));
If they are not, I will have to augment the test code to create at least one dependent entity for each dependent entity type associated with my AR.
// Create dependent State entity
var alState = //...
// Create dependent Country entity
var country = //...
Address address = null;
address = await _addressRepository.InsertAsync(new Address
(
Guid.Parse("ca846f1a-8bbd-4e2c-afbd-8e40a03ae18f"),
"7d7b348e410d48ee89e1807beb2f2ac0bd66af4ea82943ec8eee3a52962577b1",
default,
"de5ec0226aba4c1a837c9716b21af6551d10436756724d4fa507028eaaddcdadec779bea0ef04922992f9d2432068b180e6fe95f425f47c68559c1dbd4360fdb",
"53bc12edeb4544158147f3b835b0c4ce5e581844f5c248d69647d80d398706f5ee1c769e4ee14bd0a1e776a369a96ea3c0582b659ce342bdbdf40e6668f3b9f9",
"117880188dfd4a6f96892fea3e62a16f057748ebe76b4dd0a4402918e2fee9055272ff81c53d4c28825cc20d01918386864efd54e1aa458bb449a1d12b349d40",
"866a81007219411a971be2133bf4b5882d4ef612722a45ac91420e0b30d774ed",
"93bba338449444f5",
true,
true
));
address.StateId = state.Id;
address.CountryId = country.Id;
That can become a lot of objects in my hierarchy which has about 30 entities/ARs as it stands currently. This is exacerbated by multilevel dependencies.
Please help me understand the best practice in a DDD world. I need to get this right before I move into implementing 30 some-odd constructors and application services.
If your Address entity must be created with specified StateId and CountryId you need to use the original approach and force to set their value while object creation. Because, an Aggregate Root is responsible to preserve its own integrity. (See the related
documentation for more info)
I guess you also asking what will happen if the StateId does not exist in your database and if it is a just simple GUID. In such a case, if you've set your StateId as a foreign key it won't be added to your database. But if you want to query it in any way and throw an exception if it does not exist, you can create a Domain Service and check if there is a state with the given stateId and if it exists pass it to the Address constructor (if not throw an exception) and create a new address record in your database.
public class AddressManager : DomainService
{
private readonly IAddressRepository _addressRepository;
private readonly IStateRepository _stateRepository;
private readonly ICountryRepository _countryRepository;
public AddressManager(IAddressRepository addressRepository, IStateRepository stateRepository, ICountryRepository countryRepository)
{
_addressRepository = addressRepository;
_stateRepository = stateRepository;
_countryRepository = countryRepository;
}
public async Task CreateAsync(string name, AddressTypes addressType,
string line1, string line2, string line3,
string city, string postalCode,
Guid stateId, Guid countryId)
{
if(await _stateRepository.FindAsync(stateId))
{
//throw exception
return;
}
if(await _countryRepository.FindAsync(stateId))
{
//throw exception
return;
}
var address = new Address(GuidGenerator.Create(), AddressTypes.Typee, "line1", "line2", "line3", "city", "postalCode", stateId, countryId);
await _addressRepository.InsertAsync(address);
}
}
And when creating a new address call AddressManager's CreateAsync method in your app service. (You may want to set your Address entity constructor to internal instead of public to prevent creating an Address object by mistake in the application layer.)

Using #IndexingDependency derivedFrom and a property bridge

I would like to use hibernate search's #IndexingDependency with a PropertyBridge but I can't seem to make it work.
I get this error :
Hibernate ORM mapping: type 'com.something.Person': path '.currentStatus':
failures:
- HSEARCH700020: Unable to find the inverse side of the association on type
'com.something.Person' at path '.currentStatus<no value extractors>'. Hibernate Search
needs this information in order to reindex 'com.something.Person' when
'com.something.Status' is modified. You can solve this error by defining the inverse
side of this association, either with annotations specific to your integration
(#OneToMany(mappedBy = ...) in Hibernate ORM) or with the Hibernate Search
#AssociationInverseSide annotation. Alternatively, if you do not need to reindex
'com.something.Person' when 'com.something.Status' is modified, you can disable
automatic reindexing with #IndexingDependency(reindexOnUpdate = ReindexOnUpdate.SHALLOW)
Not sure if I'm doing something wrong or if what I'm trying to do isn't possible. Thank for the help.
Here are the files involved.
Person.class
#Entity
#Table
#Indexed
public class Person {
#OneToMany(mappedBy = "patient", cascade = CascadeType.ALL)
private Set<Status> status = new HashSet<>();
#Transient
#StatusBinding(fieldName = "currentStatus")
#IndexingDependency(derivedFrom = #ObjectPath(#PropertyValue(propertyName = "status")))
public Status getCurrentStatus() {
return this.status.stream()
.filter(it -> it.getDate().isAfter(LocalDate.now()))
.max(Comparator.comparing(Status::getDate))
.orElse(null);
}
}
StatusBinding.class
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.METHOD, ElementType.FIELD})
#PropertyMapping(processor = #PropertyMappingAnnotationProcessorRef(type = StatusBinding.Processor.class))
#Documented
public #interface StatusBinding {
String fieldName() default "";
class Processor implements PropertyMappingAnnotationProcessor<StatusBinding> {
#Override
public void process(PropertyMappingStep mapping, StatusBindingannotation, PropertyMappingAnnotationProcessorContext context) {
StatusBinderbinder = new StatusBinder();
if (!annotation.fieldName().isBlank()) binder.setFieldName(annotation.fieldName());
mapping.binder(binder);
}
}
}
StatusBinder.class
public class StatusBinder implements PropertyBinder {
#Setter private String fieldName = "mainStatus";
#Override
public void bind(PropertyBindingContext context) {
context.dependencies()
.use("status")
.use("date")
.use("note");
IndexSchemaObjectField mainStatusField = context.indexSchemaElement().objectField(this.fieldName);
context.bridge(Status.class, new StatusBridge(
mainStatusField.toReference(),
mainStatusField.field("status", context.typeFactory().asString()).toReference(),
mainStatusField.field("date", context.typeFactory().asLocalDate()).toReference(),
mainStatusField.field("note", context.typeFactory().asString()).toReference()
));
}
private static class StatusBrige implements PropertyBridge<Status> {
private final IndexObjectFieldReference mainStatusField;
private final IndexFieldReference<String> statusField;
private final IndexFieldReference<LocalDate> dateField;
private final IndexFieldReference<String> noteField;
public StatusBrige(
IndexObjectFieldReference mainStatusField,
IndexFieldReference<String> statusField,
IndexFieldReference<LocalDate> dateField,
IndexFieldReference<String> noteField
) {
this.mainStatusField = mainStatusField;
this.statusField = statusField;
this.dateField = dateField;
this.noteField = noteField;
}
#Override
public void write(DocumentElement target, Status mainStatus, PropertyBridgeWriteContext context) {
DocumentElement statutElement = target.addObject(this.mainStatusField);
statutElement.addValue(this.statusField, mainStatus.getStatus);
statutElement.addValue(this.dateField, mainStatus.getDate());
statutElement.addValue(this.noteField, mainStatus.getNote());
}
}
}
Problem
When a Status entity is modified, Hibernate Search doesn't know how to retrieve the corresponding Person having that Status as its currentStatus.
Solution
Assuming the currentStatus is always contained in status, and since Status.patient is the inverse side of the Person.status association, you should only need to add this:
#Transient
#StatusBinding(fieldName = "currentStatus")
#IndexingDependency(derivedFrom = #ObjectPath(#PropertyValue(propertyName = "status")))
// ADD THIS ANNOTATION
#AssociationInverseSide(
inversePath = #ObjectPath(#PropertyValue(propertyName = "patient"))
)
public Status getCurrentStatus() {
// ...
}
Why?
I'll try to explain this, but it's a bit complex, so bear with me.
Derived properties and the inverse side of associations are related concepts: they share the common purpose of allowing Hibernate Search to perform automatic reindexing.
However, they are still separate concepts, and Hibernate Search is not able to infer one from the other.
With #IndexingDependency(derivedFrom), you are defining what the computation of currentStatus depends on:
#IndexingDependency(derivedFrom = #ObjectPath(#PropertyValue(propertyName = "status")))
public Status getCurrentStatus() {
This tells Hibernate Search that currentStatus will change whenever the status property changes. With that information, Hibernate Search is able to determine that whenever you call person.getStatus().remove(...) or person.getStatus().add(...) (for example), your Person entity needs reindexing, because currentStatus is indexed, and it probably changed.
In your custom binder, you're also defining dependencies:
context.dependencies()
.use("status")
.use("date")
.use("note");
This tells Hibernate Search that whenever the status, date, and note properties of a Status entity change, the Person having that Status as its currentStatus will need reindexing.
However... what Hibernate Search doesn't know is how to retrieve the person having that Status as its currentStatus.
It may know how to retrieve all persons having that Status in their status set, but that's a different thing, isn't it? Hibernate Search doesn't know that currentStatus is actually one of the elements contained in the status property. For all it knows, getCurrentStatus() could very well be doing this: status.iterator().next().getParentStatus(). Then the current status wouldn't be included in Person#status, and it's unclear if myStatus.getPatient() could return a Person whose currentStatus is myStatus.
So you need to tell Hibernate Search explicitly: "from a given Status myStatus, if you retrieve the value of myStatus.getPatient(), you get the Person whose currentStatus property may point back to myStatus". That's exactly what #AssociationInverseSide is for.

Assign Mapped Object to Expression Result in LINQ to Entities

I have the following child object that we use an expression to map our 'entity' to our 'domain' model. We use this when specifically calling our ChildRecordService method GetChild or GetChildren:
public static Expression<Func<global::Database.Models.ChildRecord, ChildRecord>> MapChildRecordToCommon = entity => new ChildRecord
{
DateTime = entity.DateTime,
Type = entity.Type,
};
public static async Task<List<ChildRecord>> ToCommonListAsync(this IQueryable<global::Database.Models.ChildRecord> childRecords)
{
var items = await
childRecords.Select(MapChildRecordToCommon).ToListAsync().EscapeContext();
return items;
}
public async Task<List<ChildRecord>> GetChildRecords()
{
using (var uow = this.UnitOfWorkFactory.CreateReadOnly())
{
var childRecords= await uow.GetRepository<IChildRecordRepository>().GetChildRecords().ToCommonListAsync().EscapeContext();
return childRecords;
}
}
So that all works just fine. However we have another object that is a parent to that child, that in SOME cases, we also wish to get the child during the materialisation and mapping process.
In other words the standard object looks as such:
private static Expression<Func<global::Database.Models.Plot, Plot>> MapPlotToCommonBasic = (entity) => new Plot
{
Id = entity.Id,
Direction = entity.Direction,
Utc = entity.Utc,
Velocity = entity.Velocity,
};
However what I also want to map is the Plot.ChildRecord property, using the expression MapChildRecordToCommon I have already created. I made a second expression just to test this:
private static Expression<Func<global::Database.Models.Plot, Plot>> MapPlotToCommonAdvanced = (entity) => new Plot
{
ChildRecord = MapChildRecordToCommon.Compile() (entity.ChildRecord)
};
This fails:
System.NotSupportedException
The LINQ expression node type 'Invoke' is not supported in LINQ to Entities.
Is there a way to reuse my existing expression for ChildRecord, to materialise the object of ChildRecord (ie. one to one/singular not multiple) on the Plot object? I think my trouble is caused by there being just one object and being unable to use the .Select(Map) method. I am not too great at expressions and have hit a wall with this.
For reference, there are actually up to 5 or 6 other child objects on the "Plot" object that I also want to make expressions for.
I resolved this by using the third party library LinqKit.
The library allowed the use of 2 methods, .AsExpandable() (which allows for the expressions to properly compile and be invoked as I understand), and .Invoke() as an extension method to an expression, rather than calling Expression.Invoke(yourexpression). I included a null check just in case.
My code now looks as follows:
public static async Task<List<Plot>> ToCommonListAsync(this IQueryable<global::Database.Models.Plot> plots)
{
var items = await
plots.AsExpandable().Select(MapPlotToCommon).ToListAsync().EscapeContext();
return items;
}
private static Expression<Func<global::Database.Models.Plot, Plot>> MapPlotToCommon = (entity) => new Plot
{
Id = entity.Id,
Direction = entity.Direction,
Utc = entity.Utc,
Velocity = entity.Velocity,
ChildRecord = entity.ChildRecord != null ? MapChildRecordToCommon.Invoke(entity.ChildRecord) : default
};
public static Expression<Func<global::Database.Models.ChildRecord, ChildRecord>> MapChildRecordToCommon = entity => new ChildRecord
{
DateTime = entity.DateTime,
Type = entity.Type,
};

Filehelpers and Entity Framework

I'm using Filehelpers to parse a very wide, fixed format file and want to be able to take the resulting object and load it into a DB using EF. I'm getting a missing key error when I try to load the object into the DB and when I try and add an Id I get a Filehelpers error. So it seems like either fix breaks the other. I know I can map a Filehelpers object to a POCO object and load that but I'm dealing with dozens (sometimes hundreds of columns) so I would rather not have to go through that hassle.
I'm also open to other suggestions for parsing a fixed width file and loading the results into a DB. One option of course is to use an ETL tool but I'd rather do this in code.
Thanks!
This is the FileHelpers class:
public class AccountBalanceDetail
{
[FieldHidden]
public int Id; // Added to try and get EF to work
[FieldFixedLength(1)]
public string RecordNuber;
[FieldFixedLength(3)]
public string Branch;
// Additional fields below
}
And this is the method that's processing the file:
public static bool ProcessFile()
{
var dir = Properties.Settings.Default.DataDirectory;
var engine = new MultiRecordEngine(typeof(AccountBalanceHeader), typeof(AccountBalanceDetail), typeof(AccountBalanceTrailer));
engine.RecordSelector = new RecordTypeSelector(CustomSelector);
var fileName = dir + "\\MOCK_ACCTBAL_L1500.txt";
var res = engine.ReadFile(fileName);
foreach (var rec in res)
{
var type = rec.GetType();
if (type.Name == "AccountBalanceHeader") continue;
if (type.Name == "AccountBalanceTrailer") continue;
var data = rec as AccountBalanceDetail; // Throws an error if AccountBalanceDetail.Id has a getter and setter
using (var ctx = new ApplicationDbContext())
{
// Throws an error if there is no valid Id on AccountBalanceDetail
// EntityType 'AccountBalanceDetail' has no key defined. Define the key for this EntityType.
ctx.AccountBalanceDetails.Add(data);
ctx.SaveChanges();
}
//Console.WriteLine(rec.ToString());
}
return true;
}
Entity Framework needs the key to be a property, not a field, so you could try declaring it instead as:
public int Id {get; set;}
I suspect FileHelpers might well be confused by the autogenerated backing field, so you might need to do it long form in order to be able to mark the backing field with the [FieldHidden] attribute, i.e.,
[FieldHidden]
private int _Id;
public int Id
{
get { return _Id; }
set { _Id = value; }
}
However, you are trying to use the same class for two unrelated purposes and this is generally bad design. On the one hand AccountBalanceDetail is the spec for the import format. On the other you are also trying to use it to describe the Entity. Instead you should create separate classes and map between the two with a LINQ function or a library like AutoMapper.

Unit of Work, LazyLoading Disabled, Generic Repository, IncludeMultiple<T>, Http 500 error

I have a Vehicle with an association to Model, Model has an association to Make.
Here is my Generic Repository as pertaining to associations as LazyLoadingEnabled = false in my project:
public IQueryable<T> IncludeMultiple<T1>(params Expression<Func<T, object>>[] associations) where T1 : class
{
var source = (IQueryable<T>)DbContext.Set<T>();
if (associations != null)
{
foreach (Expression<Func<T, object>> path in associations)
source = DbExtensions.Include<T, object>(source, path);
}
return source;
}
In my api controller, I am using Unit of work pattern. Here is my GetAll method:
public IEnumerable<Vehicle> GetAll()
{
var vehicles = Uow.VehicleRepository.IncludeMultiple<Vehicle>(c => c.VehicleModel).ToList();
return vehicles;
}
Everything works fine and Json retrieves the Vehicle class data as well as the related VehicleModel class data.
However, Vehicle has no direct association to VehicleMake, only VehicleModel does. Now, if my GetAll method has this:
public IEnumerable<Vehicle> GetAll()
{
var vehicles = Uow.VehicleRepository.IncludeMultiple<Vehicle>(c => c.VehicleModel, c => c.VehicleModel.VehicleMake).ToList();
return vehicles;
}
while I see in debug that vehicles does indeed have the vehicles and their relevant VehicleModel and VehicleMake data, it returns a Http 500 error in Fiddler.
Update:
Added another association in Vehicle called "Test", with the GetAll method being:
(c => c.VehicleModel, c => c.Test)
No error, all data was returned via fiddler. So, it appears that a "Non-direct association" (ie Vehicle -> VehicleMake) is the cause of the error.
Question:
What would be the correct way to retrieving the relevant Vehicle data and its associated classes' data and return it to Json while not getting a Http 500 error?
*SOLVED *
This works:
public HttpResponseMessage GetAll()
{
var vehicles = from data in Uow.VehicleRepository.IncludeMultiple<Vehicle>(c => c.VehicleModel,c => c.VehicleModel.VehicleMake)
select new
{
VehDesc = data.Description,
VehVIN = data.VIN,
VehTransmissionType = data.TransmissionType,
VehFuelType = data.FuelType,
VehYear = data.Year,
VehMileage = data.Mileage,
VehCylinderSize = data.CylinderSize,
VehEngineSize = data.EngineSize,
VehVehicleModel = data.VehicleModel.Name,
VehMakeName = data.VehicleModel.VehicleMake.Name
};
return Request.CreateResponse(HttpStatusCode.OK, vehicles);
}
Basically,
1. I used an HttpResponseMessage as my return type;
2. I used projection to create an anonymous type;
Why did I have to do this?
As near as I can tell, the issue centered on JSON receiving a "circular" return with VehicleModel and VehicleMake. That is, VehicleModel had a association to VehicleMake and VehicleMake has a collection of VehicleModels. When I looked in my debug code I could see a cascade of VehicleModel to VehicleMake to VehicleModel, etc, etc, etc, so to me that meant it was circular.
If anyone knows a better way w/o using anonymous type nor removing the virtual keyword from my navigation properties, I would certainly like to know it. But this does truly work.
FinalNote: Be sure NOT to use the model's property names in anonymous type, ie replace property "TransmissionType" with something like "VehTransmissionType".