This is going to be a large and very involved project. I've been responsible for migrating Access databases to .NET many times, but never on this scale. I agree that a gradual approach will probably be the most realistic. Trying to take on everything in one shot is an easy way to fail.
As in other answers, the first and most important step will be to move everything to SQL Server. While doing this, document the database if this hasn't already been done, and identify areas for refactoring if they exist. Access databases that grow to meet evolving needs often have data models that can be improved upon when looking at the big picture.
Next, identify modules of the application that are "self contained". Because this is a do-everything database, there will probably be modules of it that are nearly completely disjoint from each other. After having these disjoint pieces, identify one of the smaller modules that has the most to gain from being updated, and take it on first.
While migrating to .NET, don't just do a simple 1 to 1 copy of the application. Gather input from users to identify pain points with the current application. You want your first migration unit to be a huge success to gain the complete buy in from everyone else.
After you have the first unit done, look at what happened in terms of challenges, difficulties, etc, and use this moving forward.
One thing that I would strongly discourage would be to implement partially working modules (ex: "we migrated the CRM, but features X,Y,Z are not in the new system yet"). This will cause users to quickly become frustrated from having an incomplete system when the old one to them was "perfectly fine". This kind of development may work fine for other domains, but not in businesses where users see "nothing wrong" with the old Access monolith and don't understand the migration needs.
Apache CXF uses the following rationale:
MinOccurs and Nillable
The default Aegis mapping is to assume that, since any Java object can be null, that the corresponding schema elements should have minOccurs of 0 and nillable of true. There are properties on the mappings to control this.
<mappings>
<mapping>
<property name='everpresentProperty' minOccurs='1' nillable='false'/>
</mapping>
<mappings>
The W3C rationale is similar:
An [XML Schema 1.0], or other [XML 1.0] document containing an [XML Schema 1.0] element , exhibits the NillableElement pattern identified using the URI [RFC 3986] http://www.w3.org/2002/ws/databinding/patterns/6/09/NillableElement when the following [XPath 2.0] expression applied to a document or element node with a context node of //xs:schema results in an [XPath 2.0] node-set containing at least one node:
.//xs:element[@nillable = 'true' and not(@minOccurs = '0')]/ (@nillable)
The following example [XML Schema 1.0] extract illustrates the use of the NillableElement pattern within an [XML Schema 1.0] document [NillableElement]:
<xs:element name="nillableMiddleName" type="ex:NillableMiddleName" />
<xs:complexType name="NillableMiddleName">
<xs:sequence>
<xs:element name="firstName" type="xs:string" />
<xs:element name="middleName" type="xs:string" nillable="true" />
<xs:element name="lastName" type="xs:string" />
</xs:sequence>
</xs:complexType>
The following example [XML 1.0] element is valid against the above example [XML Schema 1.0] when included inside an instance document [NillableElement01]:
<ex:nillableMiddleName>
<ex:firstName>Paul</ex:firstName>
<ex:middleName xsi:nil="true"/>
<ex:lastName>Downey</ex:lastName>
</ex:nillableMiddleName>
as is the following element when included in an instance document [NillableElement02]:
<ex:nillableMiddleName>
<ex:firstName>Paul</ex:firstName>
<ex:middleName>Sumner</ex:middleName>
<ex:lastName>Downey</ex:lastName>
</ex:nillableMiddleName>
References
Best Answer
The
OrderedDictionary
overloads the indexing operation so that indexing with an integerN
will get the item in positionN
, while indexing with anObject
will retrieve the item coresponding to that object. If one were to create anOrderedDictionary<int, string>
calledmyDict
, and added items (1,"George") and (0,"Fred") in that order, shouldmyDict[0]
return "George" or "Fred"?Such an issue could have been resolved by imposing a class constraint on the key type. On the other hand, much of the usefulness of generic collections stems from their ability to efficiently work with value types. Imposing a class constraint on the key type would seem a little ugly.
If the class didn't have to be CLS compliant but merely had to work with vb.net, a sensible design might have been to used named indexed properties. Thus, in the example above,
myDict.ByKey[0]
would have yielded "Fred", andmyDict.BySequence[0]
would have yielded "George". Unfortunately, languages like C# do not support named indexed properties. While one could have kludged something to allow use of the above syntax even without such properties, the unfortunate decision to wrap the fields of structures likePoint
andRectangle
means that formyDict.ByKey[0] = "Wally"
to work,myDict.ByKey
would have to return a new class object. A struct would be more efficient, but compilers would reject what looked like a write to a read-only structure (notwithstanding that the property wouldn't modify the struct returned byByKey
, but instead modify the collection to which it holds a reference).Personally, I think a dictionary-ish object that was specified as keeping track of the insertion order would be a nice thing to have; I'd also like to have a dictionary-ish object which could easily return the key associated with a particular key (so that, e.g. if one has a case-insensitive dictionary and has added a record with a key of "GEORGE", one could ask the dictionary what key is associated with "George" without having to search through all the
KeyValuePair
objects returned in an enumeration.