I am updating a record schema that I keep in mnesia. The new schema contains a new field and I would like to, after reading the record by id, check to see if the record has the field and, if not, update the record to the new schema.
So, for example our old record is like so:
-record(cust, {id, name, street_address, city, state, zip}).
The new record adds the field street_address2:
-record(cust, {id, name, street_address, street_address2, city, state, zip}).
I would like to be able to upgrade the schema of existing records on-the-fly. To do so with the current logic I would need to lookup the record by id, check the record for the existence of the address_line2 field. If it doesn't exist, set it to the atom undefined and save back to mnesia. For some reason I am having a hard time finding a good way to do this.
Any guidance would be appreciated.
According to a reply from Ulf Wiger at https://groups.google.com/forum/#!topic/erlang-programming/U6Q0-_Usb50 you do need to transform the table using mnesia:transform_table(Tab, Fun, NewAttributeList) call.
http://erldocs.com/R16B03-1/mnesia/mnesia.html?i=1&search=mnesia#mnesia
This function applies the argument Fun to all records in the table. Fun is a function which takes a record of the old type and returns a transformed record of the new type.
Alex is correct. Here's an example of using transform_table for what you described:
-record(cust, {id, name, street_address, street_address2, city, state, zip}). % This should be the record definition
mnesia:transform_table(
cust,
fun({cust,
Id,
Name,
StreetAddress,
City,
State,
Zip
}) ->
{cust,
Id,
Name,
StreetAddress,
undefined, % This is setting it to the atom undefined. You could also do "", or anything you want.
City,
State,
Zip
}
end,
record_info(fields, cust)
).
What happens is that the variables in the first tuple (Id, Name, StreetAddress, etc) get set automatically from the existing record. Then the record is transformed into the second tuple (the fun's return), using those set variables to assign the new values. This process is applied to every existing record in the table.
Keep in mind the function isn't magical in any way, so you can do anything in there that you need to, for example checking ids or whatever. But for simply adding a field to the record, you can do it like I show here.
If you're doing it from the console, be sure to load in the record definition using rr() or something.
Here's the docs for transform_table: http://www.erlang.org/doc/man/mnesia.html#transform_table-3
Related
Is there any way I can find labels which are not used in D365 FO (labels which dont have references)?
The cross references are stored in database DYNAMICSXREFDB. You can use a sql query to generate a list of labels that have no references.
This query uses two tables in the database:
Names holds an entry for each object in the application that can be referenced.
The Path field of the table holds the name of the object (e.g. /Labels/#FormRunConfiguration:ViewDefaultLabel is the path of the ViewDefaultLabel in the FormRunConfiguration label file.
Field Id is used to reference a record in this table in other tables.
References holds the actual references that connect the objects.
Field SourceId contains the Id of the Names record of the object that references another object identified by field TargetId.
The actual query could look like this:
SELECT LabelObjects.Path AS UnusedLabel
FROM [dbo].[Names] AS LabelObjects
WHERE LabelObjects.Path LIKE '/Labels/%'
AND NOT EXISTS
(SELECT *
FROM [dbo].[References] AS LabelReferences
WHERE LabelReferences.TargetId = LabelObjects.Id)
Make sure to compile the application to update the cross reference data. Otherwise the query might give you wrong results. When I run this query on a version 10.0.3 PU27 environment, it returns one standard label as a result.
In my DB, some of values of a column (called status) are null, and if they are null, I want to show a String "canceled".
Guess I need to do it on Attributes - common -if-null but then don't know how to specify it.
Can anyone help me?
There are multiple options, as you said, Attributes - common - if-null on the field containing the status should do that, you can specify a String by entering it in the Value box. If your string disappears after unfocusing, click the ... while the Value entry is selected, that will launch a Popup-entrybox.
Alternatively, you could put that logic into your query
select coalesce(status, 'Cancelled')
from table
COALESCE
Evaluates the arguments in order and returns the current value of the first expression that initially doesn't evaluate to NULL. For example, SELECT COALESCE(NULL, NULL, 'third_value', 'fourth_value'); returns the third value because the third value is the first value that isn't null.
Some databases might have similar functions with different names, with Oracle e.g. there's nvl()
I'm new to Cassandra and I created a table with a frozen collection as the primary key
cqlsh> create table rick_morty (id uuid, name text, adventure text, instigator frozen<set<text>>, PRIMARY KEY((instigator), adventure, name, id));
Now I want to query based on the primary key (instigator) for all of the values held in the collection. I have found that if I just wanted to query on 1 value, I can use CONTAINS 'contained_value', but I want to query on the entire collection.
I've been looking all over to figure out how to do this but I can't find the answer.
Doing something like
const query = 'SELECT name from rick_morty';
retrieves all results but I want to do something like...
const query = 'SELECT name from rick_morty where instigator = ["Rick", "Morty", "Beth"]';
to retrieve all list of names associated with that array of instigators.
Is this possible?? Did I just create my table in an improper way?
Is this possible??
Yes. See #8 here.
"Filter data on a column of a user-defined type. Create an index and then run a conditional query. In Cassandra 2.1.x, you need to list all components of the name column in the WHERE clause."
This should work:
SELECT name from rick_morty where instigator = { 'Rick', 'Morty', 'Beth'};
The following query should work,
SELECT name from rick_morty where instigator contains 'Rick' AND contains 'Morty';
But, This may not be an efficient/proper way to implement as Sets are meant to be used to store/get a set of data for a given primary key.
So, I would recommend you to re-design the data model by denormolise the query into a an additional table in case if this requirement is one of your primary use case.
I have taken over some code and I see that database updates are performed like this:
dbcon = DependencyService.Get<ISQLite>().GetConnection();
public void UpdateAnswered(string id)
{
lock(locker)
{
dbcon.Query<Phrase>("UPDATE Phrase SET Answered = Answered + 1 " +
"WHERE Id = ?", id);
}
}
I am new to using SQLite with Xamarin but it looks strange to me that this update is handled with a dbcon.Query and that the table name is passed as . Can someone confirm is this the optimal way to handle a table update? Also why is it coded as a query with the table name being passed?
Update<T>
This method allows you to pass in an instance of an object that this stored in the database which has a primary key. SQLite then recognizes the primary key and updates the rest of the object's values.
You would just call connection.Update( phrase ); where the phrase is an instance of the Phrase class with properties you want to set. Be aware that all columns except ID will be updated.
Query<T>
Performs a query and returns the results. The type parameter specifies the type of the items returned. This is most appropriate for SELECT queries.
Execute
This returns the number of affected rows by the query as an int. This is probably the best choice for your UPDATE query after the Update<T> method.
ExecuteScalar<T>
Use for queries that return scalar types - like COUNT, etc., where T is the type of the value.
In summary, Update is the most natural way to update a row in the database (with an instance you have), but Query<T> and Execute<T> are very useful if you just want to UPDATE one column like in your example.
Finally checked out L2E framework and ran into problems almost instantly.
Yeah, i know... i should read some books before.
Situation:
entity with props -> id and name.
entity is mapped to table, which has id and name columns.
sproc, which returns ONLY id column.
Problem:
ObjectResult<MyProp> result = _container.MyStoredProcedure(uberParameter);
Calling this will cause an error
[guilty method goes here] threw exception:
System.Data.EntityCommandExecutionException: The data reader is incompatible with the specified 'DataBase.MyPropTableObject'. A member of the type, 'name', does not have a corresponding column in the data reader with the same name..
Problem #2:
Can`t "just return" that field, cause that column has XML data type, but sproc uses fancy select statements, which causes:
Msg 421, Level 16, State 1, Line 1
The xml data type cannot be selected as DISTINCT because it is not comparable.
Question:
Is it possible to exclusively turn off mapping for this entity prop only for this one sproc?
Problem 1 is due to the proc not having the columns to populate the entity. You don't really need the proc if you have mapped the table, just select the field you want from it using linq
var result = MyEntities.EntityIMapped.First(r => r.id = uberParameter).Name;
Would give you the value from the Name column of the table for the given id. You don't need to use a stored proc for this.
Problem 2 sounds like it is in the proc, I would think that distinct on an xml data column would give a lot of results, but I'm only guessing as I don't know your solution.
This is not a direct answer for your question but, hopefully it will point you in the right direction.