EF: Adding new item in a collection and notifying all other collections that new item is added - entity-framework-4

Lest say that we have several pages that retrieve items from the same EntitySet. If I add a new entity on one page, I need to add it to both EntitySet collection and myCollection:
Context.EntitySet.Add(item);
myCollection.Add(item);
What is the best way to notify other pages that new item is added (or deleted)? Editing an entity is no problem, since all pages get change notification without any problem.

Instead of binding to different instances of IEnumerable<T> myCollection, the recommended approach is to bind directly to Context.EntitySet<T>. EntitySet<T> implements INotifyCollectionChanged and INotifyPropertyChanged interfaces. When you bind to the same instance of EntitySet<T>, each page may be notified of changes by responding to the EntitySet<T>.CollectionChanged event. For example:
// Page 1
_myCollection = Context.EntitySet<MyItem>();
_myCollection.CollectionChanged += MyItemsChanged;
...
// Page 2
_myCollection = Context.EntitySet<MyItem>();
_myCollection.CollectionChanged += MyItemsChanged;
When any page adds or removes from the collection, all pages are notified.
In regards to your comment, IEnumerable<T> does not implement the INotifyCollectionChanged interface and does not publish any change notifications. The best results come from using the EntitySet<T> directly.

Related

Grid filled by a data provider: how to trigger an action after refreshment?

In Vaadin 8.2, I have a Grid bound to a bean using a data provider (AbstractBackEndDataProvider). Data is fetched from a DB, filters are applied:
Grid grid = new Grid<>();
grid.setDataProvider(dataProvider.withConfigurableFilter()); // dataProvider derives from AbstractBackEndDataProvider<T,F>
The essential flow is the following: user inputs an item id in a form and submits, a submit event listener gets the user input, creates a new filter and updates the data provider:
filterSubmitButton.addClickListener(event -> {
try {
ItemListFilter filter = new ItemListFilter(
itemFilter.getValue(), // itemFilter = new TextField();
);
filterBinder.writeBean(filter);
dataProvider.setFilter(filter);
} catch (ValidationException e) {
//...
}
});
When the data provider gets the filter updated it calls a service to fetch new items from DB with the filter applied (to the DB query). Vaadin takes care of refreshing the Grid with new data afterwards.
What I want is to have a callback at this last moment. Say an use case would be to check if a filtered fetched result set contains only one item, to select this item in the Grid (which in its turn will trigger an event showing item details in another pane). Or to select the first grid row after initial list is loaded
But the problem is that there is neither grid.addRefreshListener() nor dataProvider.addRefreshmentListener(). Any other listeners do not seem to apply in this case.
Thanks for any help in advance.
The only solution I've found is a trade-off.
The item list presenter (which handles the view with the grid) passes its com.vaadin.event.EventRouter to dataProvider (I've modified the dataProvider to hold an EventRounter as a member). And now instead of streaming DB results directly from the dataProvider I fire an event that the data is fetched (using EventRouter). The presenter can subscribe to this event and then delegate it to the presenter of the details panel. There you can read the fetched results (the event contains them), check if there's only one entry and open it by id.
public class ListItemDataProvider extends AbstractBackEndDataProvider<Item, ItemFilter> {
//...
#Override
protected Stream<Item> fetchFromBackEnd(Query<Item, ItemFilter> query) {
// ...
List<Item> fetchedResults = service.fetch(query.getOffset(), query.getLimit(), orderBy, getFilter(query));
eventRouter.fireEvent(new FilteredDataFetchedEvent(this, fetchedResults));
return fetchedResults.stream();
}
}
#Controller
#Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class ItemListPresenter {
// ...
public void addFilteredDataFetchedListener(ItemListView.FilteredDataFetchedListener listener) {
eventRouter.addListener(FilteredDataFetchedEvent.class, listener, FilteredDataFetchedListener.FILTERED_DATA_FETCHED);
}
}
Few notes:
This is not exactly what I needed. Yes, I can do the most of my use case, if the filter is applied the list is reloaded and the details view gets the event to reload too. But I can't re-use the "selectionChanged" event listeners for this and actually can't select a row in the grid at all (just because the event from dataProdiver is thrown before the grid is updated).
This is sort of a dirty trick, because now the dataProvider throws events and deals with eventRouters of views/presenters. On the other hand Vaadins data providers anyway do allow to subscribe on events. Using that out-of-box grid-dataProvider reactive binding we just don't have an event fired after data is fetched, so we do it in a custom way.
What could also work is use the given Vaadin's subscriber dataProvider.addDataProviderListener and delegate from there an event containing the filled filter and just act independently catching that event in the details panel. But then you would need to execute sql queries twice (which can be costly) or cache them etc. This brings no benefits in comparison to the given and is still a trade-off.
When you invoke dataprovider.refreshAll(), the associated grid is automatially refreshed. Therefore, after following lines in your code:
filterBinder.writeBean(filter);
dataProvider.setFilter(filter);
add logic to get size of returned records (eg. dataprovider.size()) and if that equals one (01), invoke some other logic to select the one record and display its details in other panel.

Using a dynamic list of checkboxes in a view, how to create the model

I have an asp mvc 2 app lication where I want to display a list of check boxes that a user can select, based on a list of records in a database. To display the list my model contains a List object and the view has a foreach, and outputs Html.CheckBox for each item in the list.
Is there a way to get the model populated with the selected checkboxes, given that the model can't have specific properties for each checkbox, because the list is dynamic? Or do I have to manually iterate through the forms variables myself?
Edit: Extra details as per sabanito's comment
So in a simple view/model scenario, if my model had a property called Property1, then my view outputted a Textbox for Property1, when the form is posted via a submit button, the mvc framework will automatically populate a model with Property1 containing the text that was entered into the textbox and pass that model to the Controllers action.
Because I am dealing with a dynamic list of options the user could check, I can't write explicit boolean properties in my model and explicitly create the checkboxes in my view. Given that my list is dynamic, I'm wondering if there are ways to create my model and view so that the mvc framework is able to populate the model correctly when the form is posted.
Here's what I would do:
Are you having any issues generating the checkbox's dynamically?
If not, create a property on your ViewModel that is a:
public List<string> CheckboxResults { get; set; }
When you generate your checkbox's in the view make sure they all share the name = "CheckboxResults". When MVC see's your ViewModel as a parameter on the action method it will automatically bind and put all the "CheckboxResults" results in the List (as well as your other ViewModel properties). Now you have a dynamic List based on which checkbox's your user checked that you can send to your DomainModel or wherever.
Pretty cool stuff. Let me know if you're having issues generating the checkbox's dynamically, that's kind of a seperate issue than model binding to a list.
Use a ViewModel that reflects your view exactly, and map your domain model(s) to the viewmodel.
At first it often seems appropriate to use domain models directly in the view, for no better reason than that they're simple to use. However, as the view gets more complex over time, you end up putting a TON of conditional logic in your view, and end up with spaghetti. To alleviate this, we typically create a ViewModel that correlates 1:1 with the view.

ASP.net MVC - request-scoped global variable

I have a value which I want to be vaild during a single request. I am not using Session, as this would make the value global for the entire navigation session.
So I have put thie value in a static field of a class. Great, but then I discovered that such fields are even more global, that is, they stay set for the entire application! This means that there could be random interaction among navigation sessions.
So the question is: is there a safe place I can put a global variable, which will be
global throughout the request
reset after the request is completed
not affected by any other request, either of the same user or by other users
Thanks
Palantir
EDIT
I'll elaborate. I have a piece of code in my master page, which I need to hide on certain conditions, of which I am aware in the controller only. I thought about setting a static variable in the controller, which then would be queried by the master page, but now I see there could be a better way...
Use HttpContext.Items - a per-request cache store. Check out this article on 4guysfromrolla for more details.
It should work fine in ASP.NET MVC. You may wish to derive your master page from a base class (either via code-behind or using the Inherits directive) and have a protected method on the base class that inspects HttpContext.Items and returns, e.g. true/false depending whether you want to display the conditional code.
TempData lasts until the next request as already noted.
But there are also two other dictionaries scoped to the single request.
{Controller,ViewPage}.ViewData
Context.Items
To communicate from controller to (master) page ViewData is probably the better choice.
Two approaches come to mind:
Create a base controller where you set this variable, and then have all your controllers inherit from that.
Use TempData - the problem here being that it sticks around for the next request. But maybe knowing that, you can work around it by using a GUID key to determine that you are, in fact, getting a new value when you need it.
I would probably go with 1).
The common way to access data in a MasterPage that is set in Controller (Action) is via ViewData["TheDataKey"] = "SomeValue".
This is relatively easy and there are a couple of ways that you can do it - depending on how your site works.
I'm interpreting your request as that you want a property or variable that exists for the duration of the request and is visible to the controller, model and master.
A static property is visible to the current application in ASP this means a load of users connecting at once, but not necessarily all of them. IIS will spawn new ASP applications as it needs to.
So the ways you can do this:
You can have a custom base class for your master page or a code-behind page (as all the WebForms stuff still works)
You can have a custom base class for your controllers.
You can get to one from the other, so:
void Page_Init( object sender, EventArgs e )
{
var ctrl = this.ViewContext.Controller as MyBaseController;
if ( ctrl != null )
{
MyLocalProp = ctrl.PropOnMyController;
}
}
This will then be available in the controller and the master page on a per Request basis.
Did you look into the tempData that is attached to the controller class? it is a simple dictionary that preserves it's value through one single request.That would meant that your data can only be accessed in the controller but that should not be a problem.
public class MyController : Controller
{
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult MyAction(string id)
{
this.TempData["Message"] = "YourData";
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult MyAction(string Id)
{
var myData = this.TempData["Message"];
}
}
This works for me. I use it only to display warning messages and stuff like that.

Providing data to Menu in my ASP.NET MVC Master Page

We are beginning the process of moving from Web Forms to MVC for all of our new applications. I am working on porting our Master Page over and am trying to satisfy the requirements that we need a single master page to be used by all applications. The primary navigation for the application needs to be in a menu within the master page. Accomplishing this was easy, the hard part is that each application may need to determine what to display in the menu using a unique set of rules. Some apps can simply say, here's the menu structure to use via something like a SiteMap. Others need to determine what is displayed in the menu based on what roles the user has, this can also be handled easily with a SiteMap. The situation that I'm struggling with is that some apps need to generate the menus based on the roles the user has, but also on the data on which they are working. i.e. The same user may have different option in the menu for a page if they are working on object 'foo' than they do if working on object 'bar'.
What I've done at this point, is I've created an HtmlHelper that is called by the master page view and takes a list of objects of a custom type and returns an unordered list that is styled by a jQuery plugin to display the menu. The list of objects the helper method takes are passed to the view using the ViewData dictionary. Currently, the value of this ViewData node is set within the constructor of each controller. This allows each page, and potentially each method, to set a different menu without having to set the value in each action method, unless its needed. I have also created a class that parses a SiteMap and returns the list of items needed to build the menu. This class is what I'm using to set the ViewData value in the controller. The idea being that if an application needed more control of how the menu data was generated, they could create their own class to generate the data as long as it returns a list of the correct type of objects.
This solution seems to work fine so far, it just doesn't 'feel' right for some reason. I'm hoping that I can either get some ideas of better way to do this or some reassurance that this is a valid approach to solving this problem.
If it is something that will be on every page, do something like this:
Create a base controller:
public class MyBaseController : Controller
Have this controller get the data it needs and send that data in the ViewData["menu"] to the View. Then have all your controllers inherit from this one:
public class HomeController : MyBaseController
In the Master Page, loop through your ViewData and create your menu.
(I did something like this for my sub-menu which displayed a list of categories.)
In the book I am reading (Pro ASP.NET MVC Framework by Apress) they use Html.RenderAction for the menu in the masterpage. I am a Asp.net MVC novice so maybe somebody else can give more info about this.
You can download the sourcecode at apress.com though so maybe that could help.

ModelFactory in ASP.NET MVC to solve 'RenderPartial' issue

The 'RenderPartial()' method in ASP.NET MVC offeres a very low level of functionality. It does not provide, nor attempt to provide a true 'sub-controller' model *.
I have an increasing number of controls being rendered via 'RenderPartial()'. They fall into 3 main categories :
1) Controls that are direct
descendants of a specific page that
use that page's model
2) Controls that are direct
descendants of a specific page that
use that page's model with an
additional key of some type.
Think implementation of
'DataRepeater'.
3) Controls that represent unrelated
functionality to the page they appear
on. This could be anything from a
banner rotator, to a feedback form,
store locator, mailing list signup.
The key point being it doesn't care
what page it is put on.
Because of the way the ViewData model works there only exists one model object per request - thats to say anything the subcontrols need must be present in the page model.
Ultimately the MVC team will hopefully come out with a true 'subcontroller' model, but until then I'm just adding anything to the main page model that the child controls also need.
In the case of (3) above this means my model for 'ProductModel' may have to contain a field for 'MailingListSignup' model. Obviously that is not ideal, but i've accepted this at the best compromise with the current framework - and least likely to 'close any doors' to a future subcontroller model.
The controller should be responsible for getting the data for a model because the model should really just be a dumb data structure that doesn't know where it gets its data from. But I don't want the controller to have to create the model in several different places.
What I have begun doing is creating a factory to create me the model. This factory is called by the controller (the model doesn't know about the factory).
public static class JoinMailingListModelFactory {
public static JoinMailingListModel CreateJoinMailingListModel() {
return new JoinMailingListModel()
{
MailingLists = MailingListCache.GetPartnerMailingLists();
};
}
}
So my actual question is how are other people with this same issue actually creating the models. What is going to be the best approach for future compatibility with new MVC features?
NB: There are issues with RenderAction() that I won't go into here - not least that its only in MVCContrib and not going to be in the RTM version of ASP.NET-MVC. Other issues caused sufficent problems that I elected not to use it. So lets pretend for now that only RenderPartial() exists - or at least that thats what I've decided to use.
Instead of adding things like MailingListSignup as a property of your ProductModel, encapsulate both at the same level in a class like ProductViewModel that looks like:
public class ProductViewModel() {
public ProductModel productModel;
public MailingListSignup signup;
}
Then get your View to be strongly-typed to the ProductViewModel class. You can access the ProductModel by calling Model.productModel, and you can access the signup class using Model.signup.
This is a loose interpretation of Fowler's 'Presentation Model' (http://martinfowler.com/eaaDev/PresentationModel.html), but I've seen it used by some Microsoft devs, such as Rob Conery and Stephen Walther.
One approach I've seen for this scenario is to use an action-filter to populate the data for the partial view - i.e. subclass ActionFilterAttribute. In the OnActionExecuting, add the data into the ViewData. Then you just have to decorate the different actions that use that partial view with the filter.
There's a RenderPartial overload I use that let's you specify a new ViewData and Model:
RenderPartial code
If you look at the previous link of the MVC source code, as well as the following (look for RenderPartialInternal method):
RenderPartialInternal code
you can see that if basically copies the viewdata you pass creating a new Dictionary and sets the Model to be used in the control. So the page can have a Model, but then pass a different Model to the sub-control.
If the sub-controls aren't referred directly from the main View Model, you could do the trick Marc Gravell mentions to add your custom logic.
One method I tried was to use a strongly typed partial view with an interface. In most situations an agregated ViewModel is the better way, but I still want to share this.
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<IMailingListSignup>" %>
The Viewmodel implements the interface
public class ProductViewModel:IMailingListSignup
Thats not perfect at all but solves some issues: You can still easily map properties from your route to the model. I am not shure if you can have a route parameter map to the properties of MailingListSignup otherwise.
You still have the problem of filling the Model. If its not to late I prefer to do it in OnActionExecuted. I dont see how you can fill a Model in OnActionExecuting.

Resources