RIA Services SP2 Function Complex type not visible in Object Context - silverlight

I am struggling with returning a complex type from my services layer. It doesnt seem to be accessible from my object context.
This is the query in the service layer. All compiling fine.
public IQueryable<USP_GetPostsByThreadID_Result> uspGetPostsByThreadID(int ThreadID)
{
return this.ObjectContext.USP_GetPostsByThreadID(ThreadID).AsQueryable();
}
When I try and call it from my client, the ForumContext is not seeing it. I checked the client generated file and nothing similar is being generated. Help!!!

The name of your method may not meet the expected convention for queries. Try one or both of the following:
Add the [Query] attribute
Rename the method to GetUspPostsByThreadID
Result:
[System.ServiceModel.DomainServices.Server.Query]
public IQueryable<USP_GetPostsByThreadID_Result> GetUspPostsByThreadID(int ThreadID)
{
return this.ObjectContext.USP_GetPostsByThreadID(ThreadID).AsQueryable();
}

Its very common to have a stored procedure returning data from multiple tables. The return type doesn't fit well under any of the Entity Types(Tables). Therefore if we define Complex Type as the return collection of objects from Stored Procedure invocation, it becomes quite a powerful tool for the developer.
Following these steps I have achieved successfully the configuration of complex type on a sample AdventureWorks database.
1. Refer the picture and ensure the Stored procedure and function import is done.
2. Add the Domain Service name it as AdventureDomainService.
3. Now its time to define the tell the RIA services framework to identify my Complex Type as Entity Type. To be able to do this, we need to identify a [Key] DataAnnotation. Entity types provide data structure to the application's data model and by design, each entity type is required to define a unique entity key. We can define key on one property or a set of properties in metadata class file AdventureDomainService.metadata.cs
First define the class then add MetadatatypeAttribute like :
[MetadataTypeAttribute(typeof(CTEmployeeManagers.CTEmployeeManagersMetadata))]
public partial class CTEmployeeManagers
{
internal sealed class CTEmployeeManagersMetadata
{
private CTEmployeeManagersMetadata() { }
[Key]
public int EmployeeID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int ManagerID { get; set; }
public string ManagerFirstName { get; set; }
public string ManagerLastName { get; set; }
}
}
Define the Domain service method to return the collection of objects/entities for populating the Silverlight Grid or any other data consuming controls.
public IQueryable<CTEmployeeManagers> GetEmployeeManagers(int empId)
{
return this.ObjectContext.GetEmployeeManagers(empId).AsQueryable();
}
We define IQueryable if we are to fetch the records from datasources like SQL, whereas we define IEnumerable if we are to fetch the records from in memory collections,dictionaty,arrays.lists, etc.
Compile the server side to generate the client proxy.
In the Silverlight side open the MainPage.xaml or wherever the datagrid is put, then add following namespaces :
using System.ServiceModel.DomainServices.Client;
using SLBusinessApplication.Web;
using SLBusinessApplication.Web.Services;
..
Load the data and display:
public partial class MyPage : Page
{
AdventureDomainContext ctx = new AdventureDomainContext();
public MyPage()
{
InitializeComponent();
LoadOperation loadOp = this.ctx.Load(this.ctx.GetEmployeeManagersQuery(29));
myGrid.ItemsSource = loadOp.Entities;
}
// Executes when the user navigates to this page.
protected override void OnNavigatedTo(NavigationEventArgs e)
{
}
}
That is all that is needed to do.

It has to be part of an entity. Complex types cannot be returned by themselves

Related

Database table shows record but value is null on retrieval [duplicate]

I have some models like those below:
public class Mutant
{
public long Id { get; set; }
...
// Relations
public long OriginalCodeId { get; set; }
public virtual OriginalCode OriginalCode { get; set; }
public int DifficultyLevelId { get; set; }
public virtual DifficultyLevel DifficultyLevel { get; set; }
}
and
public class OriginalCode
{
public long Id { get; set; }
...
// Relations
public virtual List<Mutant> Mutants { get; set; }
public virtual List<OriginalCodeInputParameter> OriginalCodeInputParameters { get; set; }
}
and in the OnModelCreating of DBContext I made the relations like these:
modelBuilder.Entity<Mutant>()
.HasOne(m => m.OriginalCode)
.WithMany(oc => oc.Mutants)
.HasForeignKey(m => m.OriginalCodeId)
.OnDelete(Microsoft.EntityFrameworkCore.Metadata.DeleteBehavior.Restrict);
modelBuilder.Entity<Mutant>()
.HasOne(m => m.DifficultyLevel)
.WithMany(dl => dl.Mutants)
.HasForeignKey(m => m.DifficultyLevelId)
.OnDelete(Microsoft.EntityFrameworkCore.Metadata.DeleteBehavior.Restrict);
now when I request for Mutants, the OriginalCode is null:
but as soon as I request for OriginalCodes like below:
then the OriginalCode field of the mutants will be not null:
What is the reason and how could I fix it?
The reason is explained in the Loading Related Data section of the EF Core documentation.
The first behavior is because EF Core currently does not support lazy loading, so normally you'll get null for navigation properties until you specifically load them via eager or explicit loading. However, the Eager loading section contains the following:
Tip
Entity Framework Core will automatically fix-up navigation properties to any other entities that were previously loaded into the context instance. So even if you don't explicitly include the data for a navigation property, the property may still be populated if some or all of the related entities were previously loaded.
which explains why the navigation property is not null in the second case.
Now, I'm not sure which of the two behaviors do you want to fix, so will try to address both.
The first behavior can be "fixed" by using one of the currently available methods for loading related data, for instance eager loading:
var mutants = db.Mutants.Include(m => m.OriginalCode).ToList();
The second behavior is "by design" and cannot be controlled. If you want to avoid it, make sure to use fresh new DbContext instance just for executing a single query to retrieve the data needed, or use no tracking query.
Update: Starting with v2.1, EF Core supports Lazy Loading. However it's not enabled by default, so in order to utilize it one should mark all navigation properties virtual, install Microsoft.EntityFrameworkCore.Proxies and enable it via UseLazyLoadingProxies call, or utilize Lazy-loading without proxies - both explained with examples in the EF Core documentation.
Using Package Manager Console install Microsoft.EntityFrameworkCore.Proxies
install-package Microsoft.EntityFrameworkCore.Proxies
And then in your Context class add .UseLazyLoadingProxies():
namespace SomeAPI.EFModels
{
public partial class SomeContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder
.UseLazyLoadingProxies()
.UseSqlServer(connectionString);
}
}
}
}

breezejs createEntity is undefined

Inside an AngularJS directive, I assign a new value to a scope variable:
$scope.myPerson = { TiersId: 105191, Name: "John Smith" };
Originaly the $scope.myPerson was created from a BreezeJS entity.
Assigning the new value triggers a $scope.apply() by AngularJS, which is then intercepted by BreezeJS. That's when it gets complicated.
[EDIT]
Ok, I've figured out that I need to use the EntityManager that I've registered with my dataContext:
$scope.myPerson = myDataContext.createPerson({ TiersId: 105191, Name: "John Smith" });
function createPerson(person) {
return manager.createEntity("AccountOwner", person);
}
Now, it fails in the following code:
proto.createEntity = function (typeName, initialValues, entityState) {
entityState = entityState || EntityState.Added;
var entity = this.metadataStore
._getEntityType(typeName)
.createEntity(initialValues);
if (entityState !== EntityState.Detached) {
this.attachEntity(entity, entityState);
}
return entity;
};
The entity type is known, but the createEntity(initialValues) function is undefined. How come ?
[EDIT]
To make things clearer, here's the relevant EF mapping as well as the model classes:
public class MandateMappings : EntityTypeConfiguration<Mandate>
{
public MandateMappings()
{
Property(m => m.IBAN).HasMaxLength(34).IsFixedLength().IsUnicode(false);
Property(m => m.AccountOwner.Name).HasMaxLength(70);
Property(m => m.AccountOwner.City).HasMaxLength(500);
Property(m => m.CreatedBy).HasMaxLength(30);
Property(m => m.UpdatedBy).HasMaxLength(30);
}
}
public class Mandate : Audit
{
public string IBAN { get; set; }
public AccountOwner AccountOwner { get; set; }
}
public class AccountOwner
{
public string Name { get; set; }
public string City { get; set; }
}
public abstract class Audit
{
public DateTime CreatedDate { get; set; }
public string CreatedBy { get; set; }
}
Let me clarify what I meant when I said on User Voice that Breeze supports a form of inheritance but not "database inheritance".
I meant that, today, the classes on your server-side can be part of an inheritance chain if and only if that chain is invisible to the client.
Here are some conditions consistent with that caveat:
Only the "terminal" class in the chain (the most derived class) maps to a database table.
Properties on super classes are non-public (e.g., internal) or explicitly not mapped (e.g., adorned with [System.ComponentModel.DataAnnotations.Schema.NotMapped].
Methods may appear on any class at any level as these are never transmitted to the client.
Here is an example of a TodoItem class that inherits from a baseClass:
public class baseClass
{
public void DoNothing() {}
internal string Foo { get; set; }
}
public class TodoItem :baseClass
{
public int Id { get; set; }
[Required, StringLength(maximumLength: 30)]
public string Description { get; set; }
public System.DateTime CreatedAt { get; set; }
public bool IsDone { get; set; }
public bool IsArchived { get; set; }
}
This works fine on the server. Set a breakpoint in the controller: you'll have no trouble executing DoNothing() and getting/setting the Foo property.
This works because there is no client-side consequence of this structure. The metadata are no different after deriving from baseClass than they were before. The Foo property and DoNothing methods are invisible to the client … exactly as this service author intended.
This kind of arrangement is pretty common in the real world where the many classes of a business model share functionality through a base class.
This is NOT the end of the story and it is NOT what we think people are asking for when they ask for "inheritance".
We think people want what I have been calling "database inheritance" by which I mean that two or more classes in the inheritance chain are mapped to different tables.
Breeze does not handle that today ... in part because Breeze cannot yet comprehend metadata that describe an inheritance hierarchy.
Workaround
What if you had a class hierarchy in which data properties were defined on different class levels? You can workaround the current obstacles by providing a metadata description that flattens the hierarchy from the perspective of the client.
For example, suppose you have a Person type with FirstName and LastName. And Person derives from entityBase which defines createdBy.
If you define the Person *EntityType* to have [FirstName, LastName, and createdBy] properties - essentially flattening the hierarchy - all will be well.
Flatten the hierarchy automagically
Of course that's a PITA. One approach to inheritance we could take is to do this flattening for you when you ask Breeze to generate the metadata on the server.
I'm curious: would this suffice? Or do you really NEED to know on the JavaScript client that the createdBy property belongs to a base class. If you really need to know, please tell me why.
Edit: As of v 1.3.1 Breeze now DOES support inheritance.
Without more context I can't be sure, but I'm guessing that the issue is that Breeze does not YET have metadata about your entityType. Normally this is accomplished via your first query, but if you are creating entities before the first query then the alternative is to call the EntityManager.fetchMetadata() method instead BEFORE performing any createEntity calls. The fetchMetadata method is asynchonous, i.e. returns a promise, so you will need to perform your createEntity call inside of the 'then' portion of the promise. There are a couple of other recent 'Breeze' posts similar to this that have more details and examples.

Creating seed model from data already in DB

Is there a way to convert data in an existing database into objects that can easily be put into a seed method?
Essentially I'd like to let some people add lines to my DB via a form and then convert that into an object that I can re-seed the DB anytime I need to make changes.
The database itself is created via code-first using the following model:
public class Combo
{
public int Id { get; set; }
public string MainPrefix { get; set; }
public string MainDescriptor { get; set; }
public string MainDish { get; set; }
public string Connector { get; set; }
public string SecondaryDescriptor { get; set; }
public string SecondaryDish { get; set; }
}
High level untested idea:
Create a new T4 template which will use either your context or direct SQL to query database and generate either C# static class with method (which will return collection of object created from database data) or SQL insert commands. Depending on what you choose you will either call static method in Seed to get all entities you want to insert or simply load the created SQL script and execute it.
You can also do the same without T4 by using Code Dom (if you want to generate C# code) and creating a new custom tool for visual studio.
These features can be part of your project or the result (C# code) can be compiled in separate external assembly.

RIA Services Invoke Operation return Complex Type with Entity properties

Look at this complex type, which is basically a DTO that wraps some entities. I don't need to track these entities or use the for updating or any of that stuff, I just want to send them down to the client. The stuff at the top are non-entities just to let me know that I'm not crazy.
public class ResultDetail
{
// non entities (some are even complex) - this works GREAT!
public string WTF { get; set; }
public IEnumerable<int> WTFs { get; set; }
public SomethingElse StoneAge { get; set; }
public IEnumerable<SomethingElse> StoneAgers { get; set; }
// these are entities - none of this works
public EntityA EntityA { get; set; }
public IEnumerable<EntityB> EntityB { get; set; }
}
public class SomethingElse
{
public int ShoeString { get; set; }
}
Now look at this:
http://i.snag.gy/tI9O9.jpg
Not a single entity property shows up on the client side generated types. Are there attributes or something that I can or do I really need to create DTO objects for every one of these entity types? There are more than 2 as in my sample and they have many properties.
By the way these entity types have been generated on the client because of the normal query operations in the domain service that work with them.
This is not possible as current Ria services framework is mainly designed for tracking entities, and for Ria services it is not possible to detect which properties to serialized and which to note, since every entity has navigation properties, serializing properties may cause infinite loops or long loops as there is no control over how to navigate object graph.
Instead you are expected to program your client in such way so that you will load relations on demand correctly.

Send custom complex objects to Silverlight RIA services

I've created a complex object which itself include a list of another object.
Example:
public class MyClass1
{
private List<MyClass2> myClass2List
[Key]
public long Id { get; set; }
public string Name { get; set; }
[Include]
[Association("FK_MyClass1_MyClass2", "Id", "MyClass1Id")]
public List<MyClass2> MyClass2List
{
get
{
if (this.myClass2List == null)
{
this.myClass2List = new List<MyClass2>();
}
return this.myClass2List;
}
set { this.myClass2List = value; }
}
}
public class MyClass2
{
[Key]
public long Id { get; set; }
public string Value { get; set; }
public long MyClass1Id { get; set; }
}
Now I want to send an instance of MyClass1 (which its MyClass2List is full) to the RIA services.
My first try was creating a get method with MyClass1 return type (to expose MyClass1) and also creating an Insert method for MyClass1 and MyClass2. It works but the MyClass2 Insert method is useless! I insert all the information in MyClass1 method. Also the get method is useless!
This is the domain service that works:
[EnableClientAccess]
public class MyDomainService : DomainService
{
public MyClass1 GetMyClass1()
{
return null;
}
[Insert]
public void Insert(MyClass1 myClass1)
{
... (Main code)
}
[Insert]
public void Insert(MyClass2 myClass2)
{
// I leave this method empty because I do the job in MyClass1 Insert method.
// If I don't add this method the Add operation on MyClass2List will not work!
}
}
As you see it doesn't have a clear implementation. Although I could use the traditional WCF Silverlight-Enabled services and simply use a single method to insert the MyClass1 instance.
Note that I tried the [Invoke] method (A simple invoke method which gives the MyClass1 as an input parameter) but then "MyClass1.MyClass2List" is empty!!!
How can I send a complex object to RIA services without having such useless methods and dirty implementation? I need to do all my works just in a single method. I don't need tracking and etc here. Is it better to use the traditional WCF Services besides the RIA or is there another way about RIA?
Thanks in advance
You need to add [Composition] attribute to your one-to-many relationships as well. more info:[ +, +, + ]
Also Try to switch to "RIA Services EF Code First Support"
On the client you just call SubmitChanges on the domain context. RIA then calls the appropriate insert methods for you.

Resources