Table joins with PXDatabase SelectMulti - acumatica

Disclaimer: I'm new to C# and Acumatica Framework
I'm looking to implement a database slot however I need to pull data from joined tables. I'm using the PXDatabase.SelectMulti method from the snippet below however, I have been unable to get it to work with joins. I also can't seem to find any examples of the method with joined tables.
Is there a way to join tables with this method or perhaps another way to query the data?
public class DatabaseSlotsExample : IPrefetchable
{
protected List<string> values = new List<string>(); // store your values here
public static List<string> Values
{
get
{
//Get the values from the slot dynamically. By providing table name, you inform system when it should reset the slot.
return PXDatabase.GetSlot<DatabaseSlotsExample>("SlotSuperKey", typeof(YourTable)).values;
}
}
public void Prefetch()
{
//read database here
foreach(PXDataRecord rec in PXDatabase.SelectMulti<YourTable>(
new PXDataField<YourTable.tableField>(), //definition for fields that system should select
new PXDataFieldValue<YourTable.tableKey>("Some Condition") //definition for restriction that you need to apply
))
{
//populate your collection from the database here
values.Add(rec.GetString(0));
}
}
}

Yes, if you use BQL.Fluent as a reference, the BQL query is also simplified. See below used on Service Orders:
foreach (PXResult<FSServiceOrder> res in
SelectFrom<FSServiceOrder>.
InnerJoin<FSAppointment>.On<FSAppointment.soRefNbr.IsEqual<FSServiceOrder.refNbr>>.
InnerJoin<FSWFStage>.On<FSWFStage.wFStageID.IsEqual<FSAppointment.wFStageID>>.
InnerJoin<FSRoom>.On<FSRoom.roomID.IsEqual<FSServiceOrder.roomID>>.
InnerJoin<FSEquipment>.On<FSEquipment.registrationNbr.IsEqual<FSRoom.descr>>.
Where<FSServiceOrder.srvOrdType.IsEqual<P.AsString>.
And<FSWFStage.wFStageCD.IsEqual<P.AsString>>>.
View.Select(this, "TO", "SCHEDULED")
{
FSServiceOrder fsServiceOrder = res.GetItem<FSServiceOrder>();
FSAppointment fsAppointment = res.GetItem<FSAppointment>();
}
Then you can use the below to pull the specific table data:

Related

Check if ListBoxFor selectedValues is null before display in view?

I have a number of ListBoxFor elements on a form in edit mode. If there was data recorded in the field then the previously selected items are displaying correctly when the form opens. If the field is empty though an error is thrown as the items parameter cannot be null. Is there a way to check in the view and if there is data to use the ListBoxFor with the four parameters but if there isn't to only use three parameters, leaving out the selected items?
This is how I'm declaring the ListBoxFor:
#Html.ListBoxFor(model => model.IfQualityPoor, new MultiSelectList(ViewBag.IfPoor, "Value", "Text", ViewBag.IfQualityPoorSelected), new { #class = "chosen", multiple = "multiple" })
I'm using the ViewBag to pass the ICollection which holds the selected items as the controller then joins or splits the strings for binding to the model field. The MultiSelectLists always prove problematic for me.
Your question isn't entirely clear, but you're making it way harder on yourself than it needs to be using ListBoxFor. All you need for either DropDownListFor or ListBoxFor is an IEnumerable<SelectListItem>. Razor will take care of selecting any appropriate values based on the ModelState.
So, assuming ViewBag.IfPoor is IEnumerable<SelectListItem>, all you need in your view is:
#Html.ListBoxFor(m => m.IfQualityPoor, (IEnumerable<SelectListItem>)ViewBag.IfPoor, new { #class = "chosen" })
The correct options will be marked as selected based on the value of IfQualityPoor on your model, as they should be. Also, it's unnecessary to pass multiple = "multiple" in in your htmlAttributes param, as you get that just by using ListBoxFor rather than DropDownListFor.
It's even better if you use a view model and then add your options as a property. Then, you don't have to worry about casting in the view, which is always a good way to introduce runtime exceptions. For example:
public class FooViewModel
{
...
public IEnumerable<SelectListItem> IfQualityPoorOptions { get; set; }
}
Then, you set this in your action, before returning the view (instead of setting ViewBag). Finally, in your view:
#Html.ListBoxFor(m => m.IfQualityPoor, Model.IfQualityPoorOptions, new { #class = "chosen" })
Much simpler, and you'll never have any issues doing it that way.
UPDATE (based on comment)
The best way to handle flattening a list into a string for database storage is to use a special property for that, and then custom getter and setter to map to/from. For example:
public string IfQualityPoor
{
get { return IfQualityPoorList != null ? String.Join(",", IfQualityPoorList) : null; }
set { IfQualityPoorList = !String.IsNullOrWhiteSpace(value) ? value.Split(',').ToList() : null; }
}
[NotMapped]
public List<string> IfQualityPoorList { get; set; }
Then, you post to/interact with IfQualityPoorList, and the correct string will be set in the database automatically when you save.

Create table with custom name dynamically and insert with custom table name

I want to create the table with custom name but I cannot find the sample code. I notice the only way to create table is by generic type like db.CreateTable(). May I know if there is a way to create the table name dynamically instead of using Alias? The reason is because sometime we want to store the same object type into different tables like 2015_january_activity, 2015_february_activity.
Apart from this, the db.Insert also very limited to object type. Is there anyway to insert by passing in the table name?
I think these features are very important as it exists in NoSQL solution for long and it's very flexible. Thanks.
OrmLite is primarily a code-first ORM which uses typed POCO's to create and query the schema of matching RDMBS tables. It also supports executing Custom SQL using the Custom SQL API's.
One option to use a different table name is to change the Alias at runtime as seen in this previous answer where you can create custom extension methods to modify the name of the table, e.g:
public static class GenericTableExtensions
{
static object ExecWithAlias<T>(string table, Func<object> fn)
{
var modelDef = typeof(T).GetModelMetadata();
lock (modelDef) {
var hold = modelDef.Alias;
try {
modelDef.Alias = table;
return fn();
}
finally {
modelDef.Alias = hold;
}
}
}
public static void DropAndCreateTable<T>(this IDbConnection db, string table) {
ExecWithAlias<T>(table, () => { db.DropAndCreateTable<T>(); return null; });
}
public static long Insert<T>(this IDbConnection db, string table, T obj, bool selectIdentity = false) {
return (long)ExecWithAlias<T>(table, () => db.Insert(obj, selectIdentity));
}
public static List<T> Select<T>(this IDbConnection db, string table, Func<SqlExpression<T>, SqlExpression<T>> expression) {
return (List<T>)ExecWithAlias<T>(table, () => db.Select(expression));
}
public static int Update<T>(this IDbConnection db, string table, T item, Expression<Func<T, bool>> where) {
return (int)ExecWithAlias<T>(table, () => db.Update(item, where));
}
}
These extension methods provide additional API's that let you change the name of the table used, e.g:
var tableName = "TableA"'
db.DropAndCreateTable<GenericEntity>(tableName);
db.Insert(tableName, new GenericEntity { Id = 1, ColumnA = "A" });
var rows = db.Select<GenericEntity>(tableName, q =>
q.Where(x => x.ColumnA == "A"));
rows.PrintDump();
db.Update(tableName, new GenericEntity { ColumnA = "B" },
where: q => q.ColumnA == "A");
rows = db.Select<GenericEntity>(tableName, q =>
q.Where(x => x.ColumnA == "B"));
rows.PrintDump();
This example is also available in the GenericTableExpressions.cs integration test.

servicestack ormlite partial update

I'm using ServiceStack Ormlite to do partial update to a database table.
I have a model:
public class Model
{
public int Id;
public int Property1;
public int Property2;
public int Property3;
}
But I only want to update fields Property1, and Property2.
Does anybody know how to do this?
Thanks.
See ServiceStack's OrmLite documentation for Update statements - they contain many different different examples of partial updates.
Here is what an ServiceStack OrmLite multiple field update with where clause looks like:
Db.UpdateOnly(
new Table_DTO_Object { Field_1 = Val_1, Field_2 = Val_2, Field_3 = Val_3 },
obj => new { obj.Field_1, obj.Field_2, obj.Field_3 },
obj => obj.Id == objId);
How to update multiple fields on a single table row / with a where clause is not immediately apparent from the ServiceStack documentation because they don't have an example with both 1) multiple fields and 2) where clause.
They have an example that updates multiple fields and they have an example of an update with a where clause - really all you need to do / I did is take the needed functionality from each example.

Many tables or one table in Azure TableServiceContext file?

I'm working on creating an Azure application which would use around ten ttorage tables. I would like to adopt best practices but I am not sure if I should have just one single file with all the tables in the dataservicecontext.cs file or if I should have a different file for each table. Looks to me like both ways achieve the same thing. Anyone else have an opinion on what would be the best practice?
public class ContactDataServiceContext
: TableServiceContext
{
public ContactDataServiceContext(string baseAddress,
StorageCredentials credentials)
: base(baseAddress, credentials)
{
}
public const string ContactTableName = "ContactTable";
public IQueryable<ContactDataModel> ContactTable
{
get
{
return this.CreateQuery<ContactDataModel>(ContactTableName);
}
}
}
namespace NerdDinner.Models
{
public class NerdDinnerDataContext : TableStorageDataServiceContext
{
/// <summary>
/// Define an entry-point into our table. Dinners represents an "EntitySet".
/// </summary>
public DataServiceQuery<Dinner> Dinners
{
get
{
//Create the root of a LINQ query of type Dinner against the table Dinners
return this.CreateQuery<Dinner>("Dinners");
}
}
public DataServiceQuery<RSVP> RSVPs
{
get
{
//Create the root of a LINQ query of type RSVP against the table RSVPs
return this.CreateQuery<RSVP>("RSVPs");
}
}
}
}
To me this just comes down to code maintainability. If you favor many classes so that one class size does not grow too big, then splitting these out into separate classes might be the way to go.
There typically isn't much implementation to a table, so I think it's a bit messy to have a file per table and partial classes. You would want to group them logically so I'd recommend creating a file per Context with it's associated tables.

Rename fields in SubSonic select statement

Is there a way to rename fields when executing a select statement in SubSonic? I am using the ExecuteTypedList<MyClass> method to fill my List<MyClass> object but the properties of MyClass are not all the same as the column names from the DB table. In SQL I can do select col1 as 'FirstColumn', col2 as 'SecondColumn' from MyTable, is there a way to do something similar in SubSonic?
I believe Alias's are only available for aggregate columns.
You could just add properties of the same names as your columns to your class or a partial and map them to the properties you do use ala calculated field:
public class Songs
{
private string _songTitle;
public string SongTitle {
get { return _songTitle; }
set { _songTitle = value; }
}
public string SongName {
get { return _songTitle; }
set { _songTitle = value; }
}
}
I had the same need the other day, and added the functionality to my local copy of SubSonic. I've just submitted it a patch for it attached to this issue. Applying the patch will let you write a query like
new Select(Table1.IdColumn.AliasAs("table1ID"),
Table2.IdColumn.AliasAs("table2ID"))
.From(Table1.Schema)
.InnerJoin(Table2.Table1IdColumn, Table1.IDColumn);

Resources