Update State when another State Changes - ngxs

Let's say I have a list of products that can be filtered by type when user selects a different type from a dropdown (there are other filters users can set as well but they aren't relevant to this example).
I have State A that holds the currently filtered products. State B holds the currently selected type.
When user changes a type, I want it to also update the currently filtered products.
What is the proper way to do this?
I could call a 'set' action on State A from State B whenever State B is set
I could call a 'set' action on both State A and State B when a user sets State B
I could listen to State B in State A and update State A when State B changes
I could just have the type in State A as well, but I use the type for other separate states for other features as well

Assuming you don't want to / can't have selected type value on State A, I'd suggest a Selector on state A that depends on the state B values.
In state A:
#Selector([StateB])
static filterProducts(stateA: StateAModel, stateB: StateBModel) {
return stateA.products.filter(p => p.type === stateB.type);
}
This will be reevaluated whenever stateB changes (or state A by default in the current NGXS release). A further refined way would be having a type selector on state B.
In state B:
static #Selector()
selectedType(state: StateBModel) {
return state.type;
}
Then use that selector in state A:
#Selector([StateB.selectedType])
static filterProducts(stateA: StateAModel, selectedType: any) {
return stateA.products.filter(p => p.type === selectedType);
}
This way selectors will fire when the state changes and you don't need to add further actions.

Related

updating state of B inside useEffect with dependency on A

2 Arrays are addItems and testSelectAll, Whenever I push to addItems I also want to update testSelectAll.
addItems has individual checkbox state from the following grid while testSelectAll has per column (header) checkbox state. So in the following case, testSelectAll will have 2 items while addItems will have 6.
My useEffect is as follows:
useEffect(() => {
var check = areAllSamplesSelectedForTest(data.TestId);
if(check)
{
console.log(testSelectAll.length)
//updateSelectAll(data.TestId, true)
}
}, [addItems]);
As soon as I uncomment updateSelectAll (it updates testSelectAll), my header checkbox starts behaving abnormally
PS: I have two useEffects in my component, one is to load data one-time to table with empty array as dependencies.

Dynamic Predicate for Selecting Different Columns of an Entity

I have a requirement to showing all or less properties of an entity in the grid based on the page mode user select. For example I have three page modes
Minimal (will show 8 properties of an entity in the grid)
Standard (will show 12 properties of an entity in the grid)
Extended (will show 15 properties of an entity in the grid)
How can I make Select predicate dynamic to include the specified no of columns of an entity based on user page mode. Lets say I have Entity company with 15 properties I want to do something like this
dbContext.Companies.Select([predicate for choosing different no of columns?])
You cannot solve this using Predicates, because they always return bool.
What you need is a function expression that takes a Company object as a parameter and returns an object. Concretely, you need an Expression<Func<Company, object>>.
This is how you can define the three types of selection:
Expression<Func<Company, object>> minimal = e => new { e.Prop1, ..., e.Prop8 };
Expression<Func<Company, object>> standard = e => new { e.Prop1, ..., e.Prop12 };
Expression<Func<Company, object>> extended = e => new { e.Prop1, ..., e.Prop15 };
and then use them as you wish:
dbContext.Companies.Select(minimal);
// or
dbContext.Companies.Select(standard);
// or
dbContext.Companies.Select(extended);

How to access 1:N relationship entities in a Microsoft CRM 2011 plugin?

I have a custom Board entity with a 1:N relationship to a custom Board Seat entity. I have a post-update plugin on the Board entity that tries to loop through all the Board Seats related to the Board being updated. I've tried both a pre and post image and the relationship is null on both even though the Board has several Board Seats associated with it.
var board = EntityImage.ToEntity<my_boards>();
foreach (var seat in board.board_to_boardseat_relationship)
{
// Process each seat
}
I'm using strongly typed entities and the type of board.board_to_boardseat_relationship is System.Collections.Generic.IEnumerable<my_boardseat>. It appears that the relationship simply isn't getting populated in either the pre or post image. When I register the image I select all attributes. Any idea how to populate this relationship?
Mike,
It doesn't get populated because all the attributes are only the attributes of the Entity. You'd have to use some kind of retrieve function to get all the seats associated with this particular board. They are never included in your Post- or Pre-Image (or Target) Below is some sample code:
Entity PostImage = (Entity)m_localcontext.PluginExecutionContext.PostEntityImages["PostImage"];
my_board board = PostImage.ToEntity();
var seatsList = orgContext.CreateQuery<my_boardseat>().Where(c => c.boardId.Id == board.boardId).ToList();
if (seatsList.Count > 0)
{
foreach (my_boardseat seat in seatsList)
{
//Your Code Here
}
}

How to prevent multiple users from adding an item to a Sharepoint list simultaneously

I am using a simple form to allow people to sign up for an event. Their details are saved to a Sharepoint list. I have a quota of people who can sign up for an event (say 100 people).
How can I prevent the 100th and the 101st person from signing up concurrently, causing the quota check to allow the 101st person to sign up (because the 100th person isn't in the list yet)?
Place the ItemAdding code inside a lock statement to make sure that only one thread at a time can enter the critical section of code:
private Object _lock = new Object();
public override void ItemAdding(SPItemEventProperties properties)
{
lock(_lock)
{
// check number of the list items and cancel the event if necessary
}
}
I came up with this idea of a solution for a farm with multiple WFEs - a shared resource (a row in a table in pseudo-code above) gets locked during the time the item is added to the list:
private Object _lock = new Object();
public override void ItemAdding(SPItemEventProperties properties)
{
try
{
// 1. begin a SQL Server transaction
// 2. UPDATE dbo.SEMAPHORE
// SET STATUS = 'Busy'
// WHERE PROCESS = 'EventSignup'
lock(_lock)
{
// 3. check number of the list items and cancel the event if necessary
}
}
finally
{
// 4. UPDATE dbo.SEMAPHORE
// SET STATUS = ''
// WHERE PROCESS = 'EventSignup'
// 5. commit a SQL Server transaction
}
}
I left the lock statement because I'm not sure what will happen if the same front-end server tries to add the item #100 and #101 - will the transaction lock the row or will it not because the same connection to SQL Server will be used?
So then you can use event receivers item adding method. at item adding, your item is not created, you can calculate the current count of signed up people. if it is bigger then 100 you can cancel item adding.
but sure, more than one item adding method can be fired, to prevent that you can calculate the current count of people and increase the count +1, and keep that value somewhere else (on a field on event item perhaps) and all item adding methods can check that value before adding the item.
item added method is too late for these operations.
this would be the solution i would use.
I guess if you are updating a column, lets say - "SignUp Count", then one of the users will get the Save Conflict issue. Whoever updated the value for the first time wins and the second one will fail.
Regards,
Nitin Rastogi

Entity Framework 4.1: Possible to save a single table out of a data context containing multiple tables?

I have a chicken and egg problem, it's trivial, so I thought I would ask what's the normal pattern to save an aggregate root where all the primary keys are identity fields.
I have a typical contact entity:
Customer {
HomeAddress {
}
WorkAddress {
}
}
where both addresses are stored in the address table and the only primary key is the identity field. We check all fields against each other to keep unique address records.
Here's the problem:
I need to retrieve the Address identity field to hookup the foreign keys, so I save the Address record prior to saving the Customer record only if it's unique, otherwise I load that existing Address.
If Address is in the same DC as Customer, then customer saves too prematurely (not all records are set.)
If Address is in a separate DC, then it doesn't hookup to the Customer record that has it's own DC because you cannot have an entity associated with two DCs (can't open in one, then save in another.)
So my thinking is that I would need a separate repository for every Address, then separately load the address again in the other DC, making redundant calls to the database for the same information.
Is there a way to partially save records in a data context / container in Entity Framework 4.1? For example, to save Address by itself while still being in the same DC?
The answer to your bold question is "No" as far as I can tell. The context is a unit of work and SaveChanges commits every new, changed or deleted object to the database in a single transaction. You cannot selectively say: Save only this or that object or save only entities in state Added and don't commit entities in state Modified or Deleted or something.
As a workaround you could try that:
using (var context1 = new MyContext())
{
Address address = context1.Addresses.Where(predicate).FirstOrDefault();
// if address != null it is attached now to context1
if (address == null)
{
// ... otherwise create new address in another context and save
using (var context2 = new MyContext())
{
address = new Address { Name = name, ... }
context2.Addresses.Add(address);
context2.SaveChanges();
} // context2 destroyed now and address is not attached to it anymore
// ... and attach to context1
context1.Addresses.Attach(address);
}
customer.HomeAddress = address;
// ...
context1.SaveChanges();
}
This way address is never attached to the two contexts at the same time. I am not sure though if this works.
Edit
I must add (because my code above looks so weird) that "normally" you could do all this in context1 alone. But I understood your point 2 this way that there is something happening in // ... (which I don't understand) before SaveChanges which prevents you to save the new address and the customer at the same time.

Resources