Creating Test EntityList objects - RIA Services - silverlight

I'm creating an EnityList to do some client side testing with my ViewModel. Something like:
var people = new EntityList<Person>()
{
new Incident() {Age = 55, Name="Joe"},
new Incident() {Age=42, Name="Sam"}
};
The problem is that the implicit (and explicit) Adds fail. The entitylist is created as read-only. Any thoughts on how to create a test EntityList?

If you're doing testing then you probably don't want an EntityList. I would expect that a ViewModel shouldn't know about the EntityList, but rather should just get access to an IEnumberable instead. Both EntityList and List expose this, so in your tests you can just create a List.
I realize this doesn't help with the issue of EntityList being read-only. :)

I think you also need an EntityContainer to own your EntityList.

Related

Merging two database tables into a single Vaadin Treetable

TL;DR: How do I combine info from two database tables into a Vaadin Treetable (or, when Vaadin 7.5 is released, a heirarchical Grid)?
I have a Java Swing desktop application that does this currently, albeit probably very ineffeciently with ArrayLists of Java Beans that updates from the SQL Server every 30 seconds. Well, I'm now attempting to port this desktop app over to a Vaadin web app. The desktop app has login capabilities and I'll eventually worry about doing the same for the web app, but for now, I just want to try and get the most basic part of this web app working: The Treetable. Or, hopefully soon, a heirarchical Grid.
To help illustrate what I'm aiming for, I'll try and post an image I created that should show how the data from the two tables needs to merge into the treetable (using a partial screenshot of my existing desktop app):
I am well aware of how to use the JOIN command in SQL and I've briefly read about Referencing Another SQLContainer, but I'm still in the early stages of learning Vaadin and still trying to wrap my head around SQLContainer, FreeformQuery, and how I need to implement FreeformStatementDelegate for my project. Not to mention that I'll need to implement checkboxes for each row, as you can see in that photo, so that it updates the database when they are clicked. And a semi-checked state for the checkbox would be necessary for Jobs that have more than one OrderDetail item wherein only some of those OrderDetail items are completed. To get that working for my Java Swing program, I had to lean on an expert Java developer who already had most of the code ready, and boy, is it super-complicated!
If anyone can give me a high-level view of how to accomplish this task along with some examples, I would be indebted. I totally understand that I'm asking for a great deal here, and I'm willing to take it slow, step-by-step, as long as you are. I really want to fully understand this so I'm not just copy-pasting code without thinking.
I have never used SQLContainer so this might not be the answer you want. I just had a quick look at SQLContainer and I'm not sure if it will serve your purpose. For a TreeTable you will need a Container Implementing the Container.Hierarchical interface or the table will put a wrapper around it and you have to set the parent-children relations manually. You probably could extend SQLContainer and implement the methods from Container.Hierarchical in that class but this might get complicated.
In your situation I think I'd go with implementing my own Container, probably extending AbstractContainer, to get the listener code for free, and implementing Hierarchical. There are quite some methods to implement, I know, and so this will need some time, but most methods are quickly implemented and you can start with the basic methods and add more interfaces (Ordered, Sortable, Indexed, Filterable, Collapsible,...) later.
If done properly you'll end up with with easy readable code that can be extended in the future without to much trouble and you will not depend on future versions of SQLContainer.
Another good thing is that you'll learn a lot about the data structures (Container, Item, Property) used in vaadin. But as I said I don't really know SQLContainer so maybe there will be a better answer telling you that it is easy with the SQLContainer
For the Checkbox feature you could go display the name/product property as a CheckBox. With Icon and Caption it looks almost like you want it. See http://demo.vaadin.com/sampler/#ui/data-input/other/check-box and set an Icon. The semi-checked state could be done with css.
Hope this helps you finding the right solution for your task.
I'll admit that I'm a beginner with vaadin myself and there may be much better ways of doing this, but here's something I've mocked up which seems to work. It doesn't do everything you need but it might be a base to start from. Most importantly, for changes to be saved back into the database you'll need to update the SQLContainers when something in the container is changed.
import com.vaadin.data.Item;
import com.vaadin.data.Property;
import com.vaadin.data.util.HierarchicalContainer;
import com.vaadin.data.util.sqlcontainer.SQLContainer;
#SuppressWarnings("serial")
public class TwoTableHierarchicalContainer extends HierarchicalContainer {
private SQLContainer parentContainer;
private SQLContainer childContainer;
private String parentPrimaryKey;
private String childForeignKey;
public TwoTableHierarchicalContainer(SQLContainer parentContainer, SQLContainer childContainer,
String parentPrimaryKey, String childForeignKey) {
this.parentContainer = parentContainer;
this.childContainer = childContainer;
this.parentPrimaryKey = parentPrimaryKey;
this.childForeignKey = childForeignKey;
init();
}
private void init() {
for (Object containerPropertyIds : parentContainer.getContainerPropertyIds()) {
addContainerProperty(containerPropertyIds, Object.class, "");
}
for (Object containerPropertyIds : childContainer.getContainerPropertyIds()) {
addContainerProperty(containerPropertyIds, Object.class, "");
}
for (Object itemId : parentContainer.getItemIds()) {
Item parent = parentContainer.getItem(itemId);
Object newParentId = parent.getItemProperty(parentPrimaryKey).getValue();
Item newParent = addItem(newParentId);
setChildrenAllowed(newParentId, false);
for (Object propertyId : parent.getItemPropertyIds()) {
#SuppressWarnings("unchecked")
Property<Object> newProperty = newParent.getItemProperty(propertyId);
newProperty.setValue(parent.getItemProperty(propertyId).getValue());
}
}
for (Object itemId : childContainer.getItemIds()) {
Item child = childContainer.getItem(itemId);
Object newParentId = child.getItemProperty(childForeignKey).getValue();
Object newChildId = addItem();
Item newChild = getItem(newChildId);
setChildrenAllowed(newParentId, true);
setParent(newChildId, newParentId);
setChildrenAllowed(newChildId, false);
for (Object propertyId : child.getItemPropertyIds()) {
#SuppressWarnings("unchecked")
Property<Object> newProperty = newChild.getItemProperty(propertyId);
newProperty.setValue(child.getItemProperty(propertyId).getValue());
}
}
}
}

RegisterMultiple does not keep implementation type as singleton if registered as multiple registration types?

I am trying to add a type called TypeA as two different registration types: InterfaceA and InterfaceB.
container.RegisterMultiple(typeof(InterfaceA), new[] {typeof(TypeA), typeof(TypeB)});
container.RegisterMultiple(typeof(InterfaceB), new[] {typeof(TypeA), typeof(TypeC)});
But when I Resolve them, I get one instance of TypeA when resolving InterfaceA, and another instance when resolving InterfaceB. I expect to get the same instance for both resolves, but I am not.
I have also tried to add .AsSingleton() to the call, but it made no difference.
Am I doing something wrong, or does anyone have any ideas of doing this without adding a TypeAFactory or such that keeps track of the instances instead?
Thanks in advance for any help.
I think what you are seeing is by design.
To get the same instance for both interfaces you can create the instance yourself and register it for both interfaces:
var instanceOfA = new TypeA(...);
container.Register<InterfaceA>(instanceOfA);
container.Register<InterfaceB>(instanceOfA);
I solved this on my own with a quite ugly (but yet quite elegant) solution.
I create another, internal, instance of a TinyIoCContainer, and I register all my types with the actual TinyIoCContainer.Current by giving it a factory in the form of:
var container = TinyIoCContainer.Current;
var internalIoC = new TinyIoCContainer();
Dictionary<Type, Object> instances = new Dictionary<Type, Object>();
...
Func<TinyIoCContainer, NamedParameterOverloads, Object> factory = (TinyIoCContainer c, NamedParameterOverloads o) =>
{
if (instances.ContainsKey(implementationType) == false)
{
// Create the instance only once, and save it to our dictionary.
// This way we can get singleton implementations of multi-registered types.
instances.Add(implementationType, internalIoC.Resolve(implementationType));
}
return instances[implementationType];
};
container.Register(registerType, factory, implementationType.FullName);
I'm sure there will be a few caveats with this solution, but I'm also sure I'll be able to figure out a workable fix for them, as things look right now.

New to AutoFixture trying to get my head around it and I can't see it helping me

Currently, I'm using custom made fake objects that behind the scenes use NSubstitute which creates the actual objects but it's becoming very hard to maintain as the project grows, so I'm trying to find alternatives and I'm hoping that AutoFixture is the right tool for the job.
I read the documentation and I'm struggling because there's very little to no documentation and I read most of the blog posts by Mark Seemann including the CheatSheet.
One of the things that I'm having hard time to grasp is how to create an object with a constructor that have parameters, in my case I need to pass argument to CsEmbeddedRazorViewEngine as well as HttpRequestBase to ControllerContext.
The way I see it is that I need to create a fake objects and finally create a customization object that injects them to
I also looked into NBuilder it seems slightly more trivial to pass arguments there but I've heard good things about AutoFixture and I would like to give it a try. :)
I'm trying to reduce the amount of fake objects I have so here is a real test, how can I do the same thing with AutoFixture?
[Theory,
InlineData("en-US"),
InlineData("en-us"),
InlineData("en")]
public void Should_return_the_default_path_of_the_view_for_enUS(string language)
{
// Arrange
const string EXPECTED_VIEW_PATH = "~/MyAssemblyName/Views/Home/Index.cshtml";
CsEmbeddedRazorViewEngine engine = CsEmbeddedRazorViewEngineFactory.Create(ASSEMBLY_NAME, VIEW_PATH, string.Empty);
string[] userLanguage = { language };
HttpRequestBase request = FakeHttpRequestFactory.Create(userLanguage);
ControllerContext controllerContext = FakeControllerContextFactory.Create(request);
// Act
ViewEngineResult result = engine.FindPartialView(controllerContext, VIEW_NAME, false);
// Assert
RazorView razorView = (RazorView)result.View;
string actualViewPath = razorView.ViewPath;
actualViewPath.Should().Be(EXPECTED_VIEW_PATH);
}
P.S. I'm using xUnit as my testing framework and NSubstitute as my mocking framework should I install both AutoFixture.Xunit and AutoFixture.AutoNSubstitute?
UPDATE: After learning more and more about it I guess it is not the right tool for the job because I tried to replace my test doubles factories with AutoFixture rather than setting up my SUT with it.
Due to odd reason I thought it's doing the same thing NBuilder is doing and from what I can see they are very different tools.
So after some thinking I think I'll go and change the methods I have on my test doubles factories to objects then use AutoFixture to create my SUT and inject my test doubles to it.
Note: I don't have the source code for the CsEmbeddedRazorViewEngine type and all the other custom types.
Here is how it could be written with AutoFixture:
[Theory]
[InlineAutoWebData("en-US", "about", "~/MyAssemblyName/Views/Home/Index.cshtml")]
[InlineAutoWebData("en-US", "other", "~/MyAssemblyName/Views/Home/Index.cshtml")]
public void Should_return_the_default_path_of_the_view_for_enUS(
string language,
string viewName,
string expected,
ControllerContext controllerContext,
CsEmbeddedRazorViewEngine sut)
{
var result = sut.FindPartialView(controllerContext, viewName, false);
var actual = ((RazorView)result.View).ViewPath;
actual.Should().Be(expected);
}
How it works:
It uses AutoFixture itself together with it's glue libraries for xUnit.net and NSubstitute:
PM> Install-Package AutoFixture.Xunit
PM> Install-Package AutoFixture.AutoNSubstitute
With InlineAutoWebData you actually combine inline values and auto-generated data values by AutoFixture – also including Auto-Mocking with NSubstitute.
internal class InlineAutoWebDataAttribute : CompositeDataAttribute
{
internal InlineAutoWebDataAttribute(params object[] values)
: base(
new InlineDataAttribute(values),
new CompositeDataAttribute(
new AutoDataAttribute(
new Fixture().Customize(
new WebModelCustomization()))))
{
}
}
Remarks:
You could actually replace the WebModelCustomization customization above with AutoNSubstituteCustomization and it could work.
However, assuming that you are using ASP.NET MVC 4, you need to customize the Fixture instance with:
internal class WebModelCustomization : CompositeCustomization
{
internal WebModelCustomization()
: base(
new MvcCustomization(),
new AutoNSubstituteCustomization())
{
}
private class MvcCustomization : ICustomization
{
public void Customize(IFixture fixture)
{
fixture.Customize<ControllerContext>(c => c
.Without(x => x.DisplayMode));
// Customize the CsEmbeddedRazorViewEngine type here.
}
}
}
Further reading:
Encapsulating AutoFixture Customizations
AutoData Theories with AutoFixture
I ended up doing this.
[Theory,
InlineData("en-US", "Index", "~/MyAssemblyName/Views/Home/Index.cshtml"),
InlineData("en-us", "Index", "~/MyAssemblyName/Views/Home/Index.cshtml"),
InlineData("en", "Index", "~/MyAssemblyName/Views/Home/Index.cshtml")]
public void Should_return_the_default_path_of_the_view(string language, string viewName, string expected)
{
// Arrange
CsEmbeddedRazorViewEngine engine = new CsEmbeddedRazorViewEngineFixture();
ControllerContext controllerContext = FakeControllerContextBuilder.WithLanguage(language).Build();
// Act
ViewEngineResult result = engine.FindPartialView(controllerContext, viewName, false);
// Assert
string actualViewPath = ((RazorView)result.View).ViewPath;
actualViewPath.Should().Be(expected);
}
I encapsulated the details to setup my SUT into a fixture and used the builder pattern to handle my fakes, I think that it's readable and pretty straightforward now.
While AutoFixture looks pretty cool, the learning curve seems long and I will need to invest enough time to understand it, for now, I want to clean-up my unit tests and make them more readable. :)

XmlSerializer stopped working after updates

I'm using XmlSerializer. I've had no problems with it until now. I updated Silverlight from 4 to 5 and at the same time also updated the WCF RIA Services from v1 SP1 to v1 SP2. Now the following line gives me an error.
XmlSerializer s = new XmlSerializer(typeof(MyCustomObject));
The error is:
System.InvalidOperationException: System.ServiceModel.DomainServices.Client.EntityConflict cannot be serialized because it does not have a parameterless constructor.
The object I'm using (MyCustomObject in the sample) has not changed in any way so I'm starting to think it's either SL5 or the new RIA Services that is breaking my code. I didn't find any breaking changes document or mentions that this could happen. I don't know why it has a problem with EntityConflict since I'm not using any entities within my object.
Has anyone seen an error like this and/or know how to solve it?
UPDATE!
The final property that the error message says before EntityConflict is an Entity. I think that makes a difference but it has been working before. I'd also like to know why the serializer already tries to serialize the object in the constructor?
public static XmlSerializer GetEntityXmlSerializer<TEntity>()
where TEntity : Entity
{
XmlAttributes ignoreAttribute = new XmlAttributes()
{
XmlIgnore = true,
};
// use base class of Entity,
// if you use type of implementation
// you will get the error.
Type entityType = typeof(Entity);
var xmlAttributeOverrides = new XmlAttributeOverrides();
xmlAttributeOverrides.Add(entityType, "EntityConflict", ignoreAttribute);
xmlAttributeOverrides.Add(entityType, "EntityState", ignoreAttribute);
return new XmlSerializer(typeof(TEntity), xmlAttributeOverrides);
}
I am not sure why this would be happening, RIA Services entities are not XmlSerializable objects and the entities themselves are not decorated with the [Serializable] attribute. Have you added partial classes on the client side which decorate the entities with [Serializable] or modified the code generation in some way?
I got around this problem by using intermediary serializable POCO objects which were copies of my custom objects (which were inherited from Entity). The POCO objects did not inherit from Entity. I just updated their values from the original Entity objects. They then serialized quite nicely. Of course, when you de-serialize you need to update your Entity objects from the POCO objects.

How to get can CanAddNew to be true for a collection returned by RIA Services

RIA Services is returning a list of Entities that won't allow me to add new items. Here are what I believe to be the pertinent details:
I'm using the released versions of Silverlight 4 and RIA Services 1.0 from mid-April of 2010.
I have a DomainService with a query method that returns List<ParentObject>.
ParentObject includes a property called "Children" that is defined as List<ChildObject>.
In the DomainService I have defined CRUD methods for ParentObject with appropriate attributes for the Query, Delete, Insert, and Update functions.
The ParentObject class has an Id property marked with the [Key] attribute. It also has the "Children" property marked with the attributes [Include], [Composition], and [Association("Parent_Child", "Id",
"ParentId")].
The ChildObject class has an Id marked with the [Key] attribute as well as a foreign key, "ParentId", that contains the Id of the parent.
On the client side, data is successfully returned and I assign the results of the query to a PagedCollectionView like this:
_pagedCollectionView = new PagedCollectionView(loadOperation.Entities);
When I try to add a new ParentObject to the PagedCollectionView like this:
ParentObject newParentObject = (ParentObject)_pagedCollectionView.AddNew();
I get the following error:
" 'Add New' is not allowed for this view."
On further investigation, I found that _pagedCollectionView.CanAddNew is "false" and cannot be changed because the property is read-only.
I need to be able to add and edit ParentObjects (with their related children, of course) to the PagedCollectionView. What do I need to do?
I was just playing around with a solution yesterday and feel pretty good about how it works. The reason you can't add is the source collection (op.Entities) is read-only. However, even if you could add to the collection, you'd still want to be adding to the EntitySet as well. I created a intermediate collection that takes care of both these things for me.
public class EntityList<T> : ObservableCollection<T> where T : Entity
{
private EntitySet<T> _entitySet;
public EntityList(IEnumerable<T> source, EntitySet<T> entitySet)
: base(source)
{
if (entitySet == null)
{
throw new ArgumentNullException("entitySet");
}
this._entitySet = entitySet;
}
protected override void InsertItem(int index, T item)
{
base.InsertItem(index, item);
if (!this._entitySet.Contains(item))
{
this._entitySet.Add(item);
}
}
protected override void RemoveItem(int index)
{
T item = this[index];
base.RemoveItem(index);
if (this._entitySet.Contains(item))
{
this._entitySet.Remove(item);
}
}
}
Then, I use it in code like this.
dataGrid.ItemsSource = new EntityList<Entity1>(op.Entities, context.Entity1s);
The only caveat is this collection does not actively update off the EntitySet. If you were binding to op.Entities, though, I assume that's what you'd expect.
[Edit]
A second caveat is this type is designed for binding. For full use of the available List operation (Clear, etc), you'd need to override a few of the other methods to write-though as well.
I'm planning to put together a post that explains this a little more in-depth, but for now, I hope this is enough.
Kyle
Here's a workaround which I am using:
Instead of using the AddNew, on your DomainContext you can retrieve an EntitySet<T> by saying Context.EntityNamePlural (ie: Context.Users = EntitySet<User> )
You can add a new entity to that EntitySet by calling Add() and then Context.SubmitChanges() to send it to the DB. To reflect the changes on the client you will need to Reload (Context.Load())
I just made this work about 15mins ago after having no luck with the PCV so I am sure it could be made to work better, but hopefully this will get you moving forward.
For my particular situation, I believe the best fit is this (Your Mileage May Vary):
Use a PagedCollectionView (PCV) as a wrapper around the context.EntityNamePlural (in my case, context.ParentObjects) which is an EntitySet. (Using loadOperation.Entities doesn't work for me because it is always read-only.)
_pagedCollectionView = new PagedCollectionView(context.ParentObjects);
Then bind to the PCV, but perform add/delete directly against the context.EntityNamePlural EntitySet. The PCV automatically syncs to the changes done to the underlying EntitySet so this approach means I don't need to worry about sync issues.
context.ParentObjects.Add();
(The reason for performing add/delete directly against the EntitySet instead of using the PCV is that PCV's implementation of IEditableCollectionView is incompatible with EntitySet causing IEditableCollectionView.CanAddNew to be "false" even though the underlying EntitySet supports this function.)
I think Kyle McClellan's approach (see his answer) may be preferred by some because it encapsulates the changes to the EntitySet, but I found that for my purposes it was unneccessary to add the ObservableCollection wrapper around loadOperation.Entities.
Many thanks to to Dallas Kinzel for his tips along the way!

Resources